Open Erapchu opened 3 years ago
Duplicate of #2158 ?
@lindexi Looks like yes. Disable HW acceleration or don't use BitmapCache at all - is not a good idea. Issue #2158 is quite old. I faced it again and temporary solution is disable BitmapCache but performance is bad.
@Erapchu: Thank you for the report and investigation. Are you okay with us closing this as a duplicate? Thanks.
Of course. But I want to know why it's happen and how to resolve for now. Future - update will be applied to new .NET version? Not for old like .NET framework?
@Erapchu - it will be applied to the new .NET version. I will be serviced down to .NET Framework based on community intertest/upvoting. And we would like to track these community responses via a single bug/Issue. Let us use this new one and close #2158
I did some investigations. If OS bring up any full-screen window (like UAC prompt when application required administrator or Ctrl + Alt + Del or sign-out), I faced that issue again. Why BitmapCache broke all windows and how to detect it? Can I subscribe WPF window to WndProc and listen for messages to catch when need to restart rendering (one more question how to do it?). We just using BitmapCache to improve rendering animations. Can we use something different, because this element invokes problems.
Setting up BitmapCache to root Grid of the window and Ctrl + Alt + Del invokes problem even if first window was showed, but not focused. When rendering suspended, WM_PAINT received by window in infinite loop. When remove BitmapCache, problem is vanished, until set it again. When hover mouse over very first window, ALL OTHER windows with BitmapCache rendering normally. Can anyone deep dive in that problem? @predavid @ryalanms develop branch was updated here - https://github.com/Erapchu/GhostWindows
We are also stuck with this problem, before in Windows 7 it was much less problematic, we only had to force an invalidate visual and it seemed to fix the issue. But in Windows 10 now it is much worst, I can't believe Microsoft does not fix such a huge bug.
We can't disable the bitmap cache and can't disable HW acceleration, because we have a very big complex application, we can't simply close and re-open the window.
And knowing that the original bug since windows 7 was never work on ... I have very low expectation from Microsoft, so we had to find a work around.
So, if anyone is looking for an other workaround... it's a bit nasty but I think it is the only way to recover while keeping your current WPF window open, if you can run with admin privilege, you have to kill dwm.exe everything will flicker and recover.
If you can't run as admin, you have to create a GPU virus and hang it out in an infinite loop, that trigger the hang device watch dog of Windows that unload and reload this device, here is how to do it programmatically, last answer here: https://gamedev.stackexchange.com/questions/108141/how-can-i-test-dxgi-error-device-removed-error-handling
This work surprising well, after all the screen flicker for couple of seconds everything is back working.
Now our only last issue is to detect when we have to run that virus, we can detect the session unlock but not the UAC security prompt (only work with admin right)
@HyksosSowo the only one solution is don't hide windows, but close and re-open them. Close it completely when bitmapcache is in visual tree Anyway we need to sacrifice something
Hey, we've been running into this issue for a while as well and have finally come to a stable (but not ideal) solution to this issue.
When creating a window make sure to set AllowsTransparency
to true (This will also require setting WindowStyle
to None meaning a custom style and Window class will be needed to add back the default windows functionality).
I couldn't tell you why this works unfortunately (but hopefully it can help narrow down the issue).
I've tried setting AllowsTransparency
on only windows using BitmapCache
but it will still cause the problem unless all windows use it.
It's also worth noting that if you're creating WS_CHILD
window's you'll also need to set the minimum supported OS to windows 8 or higher inside the app.manifest file
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
</application>
</compatibility>
I hope this helps someone out there, as it was a huge pain to find!
Can still reproduce in .NET8. I'm trying to mitigate the issue by invalidating all UIElement.CacheMode within a window. But as soon as you restore any CacheMode, WM_PAINT frenzy start all over again. And if you don't restore CacheMode you're still getting half frozen DropDown elements.
hwndSource = PresentationSource.FromVisual(this) as HwndSource;
hwndSource.AddHook(WndProc);
const int WM_PAINT = 0x000F;
private Timer WM_PAINT_TIMER;
private Dictionary<UIElement, CacheMode> cacheModes = new();
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case WM_PAINT:
{
// Loop through all visual elements in the window
foreach (var element in WPFUtils.FindVisualChildren<UIElement>(this))
{
if (element.CacheMode is null)
continue;
// Store the previous CacheMode value
cacheModes[element] = element.CacheMode.Clone();
// Set the CacheMode to null
element.CacheMode = null;
}
WM_PAINT_TIMER.Stop();
WM_PAINT_TIMER.Start();
}
break;
}
return IntPtr.Zero;
};
private void WM_PAINT_TIMER_Tick(object? sender, EventArgs e)
{
// UI thread
Application.Current.Dispatcher.Invoke(() =>
{
// Set the CacheMode back to the previous value
foreach (UIElement element in cacheModes.Keys)
element.CacheMode = cacheModes[element];
});
}
// Helper method to find all visual children of a given type
public static IEnumerable<T> FindVisualChildren<T>(DependencyObject parent) where T : DependencyObject
{
if (parent != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
if (child is T)
{
yield return (T)child;
}
foreach (var childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
@HyksosSowo the only one solution is don't hide windows, but close and re-open them. Close it completely when bitmapcache is in visual tree Anyway we need to sacrifice something
@Erapchu we can't close the window. We also can't use the transparency trick as our WPF window is inside a HwndSource.
The GPU virus is still the only solution that reliably work.
@HyksosSowo try to disable hardware acceleration for that window
https://stackoverflow.com/questions/2169600/how-hardware-acceleration-can-be-disabled-in-wpf
@HyksosSowo try to disable hardware acceleration for that window
https://stackoverflow.com/questions/2169600/how-hardware-acceleration-can-be-disabled-in-wpf
Obviously it works but it's like turning off a few cylinder of your engine because it misbehaves. It suxx...
We are not using WPF for simple dialog box, we are using it to load huge animated graphics, we can't use software rendering... and the funny thing is to get good performance we need HW acceleration + bitmap cache or else it suxx.
I also faced same issue, I am using many HLSL shaders and D3DImage in my WPF UI.
Only solution I came up with is to create a empty D3DImage and assign IsFrontBufferAvailableChanged event.
internal void IsFrontBufferAvailableChanged_Event (object sender, DependencyPropertyChangedEventArgs e)
{
if (D3DImageSource.IsFrontBufferAvailable)
{
// Recover from software rendering and switch back to HW acceleration
System.Windows.Media.RenderOptions.ProcessRenderMode = RenderMode.Default;
}
else
{
// Will stop WM_PAINT flood
System.Windows.Media.RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;
}
}
Keep this D3DImage somewhere hidden in your window, This works fine and will invalidate BitmapCache
objects but the side effect is your UI will flick for ~2 seconds before recovering from WM_PAINT flood.
NEW UPDATE I started digging more and deep dived in wpfgfx and native core. I came up with a very good solution, You can check it out at : https://github.com/CycloneRing/WpfBitmapCacheIssue
Here's a solid solution and it also smooth out animations : https://github.com/CycloneRing/WpfBitmapCacheIssue/tree/mc-hook
Does the bug reproduce also in WPF for .NET Framework 4.8?: Yes, also .NET Framework 4.5.2, and all .NET Core versions.
Problem description: WPF windows stop rendering at all when use BitmapCache on any window's control or root control and first shown WPF window was hidden by set Visibility to Hidden or call Hide() method.
Actual behavior: There's no exceptions or fatal crashes. All WPF windows that use BitmapCache just stop rendering at all! While FIRST hidden window will not be shown.
Expected behavior: WPF Windows should render normally.
Minimal repro: Please follow this steps to catch problem on your machine or build any project below. Please, help me resolve it.
https://github.com/Erapchu/GhostWindows https://github.com/Erapchu/GhostWindowsCore
In App.xaml.cs OnStartup overrided method:
var window1 = new MainWindow(); window1.Show(); await Task.Delay(1000); window1.Hide(); var window2 = new MainWindow(); window2.Show();