dotnet / dotnet/wpf

Massive use of BitmapCache leads to UCEERR_RENDERTHREADFAILURE

Open
#8,031 3 comments 0 reactions 0 assignees View on GitHub
Investigate
Dominant language
C#
Stars
7.7k
Forks
1.3k
Avg merge
1d 11h
Merged PRs (30d)
61

Description

### Description

When BitmapCache is enabled for ~5000 UIElements, the rendering thread fails.

### Reproduction Steps

A small project with a button to reproduce the problem: https://github.com/reejk/WpfBitmapCacheRenderThreadFail.
Or just create about 5000 UIElements with `CacheMode = BitmapCache`

### Expected behavior

The render thread does not fail.

### Actual behavior

```
System.Runtime.InteropServices.COMException (0x88980406): UCEERR_RENDERTHREADFAILURE (0x88980406)
at System.Windows.Media.Composition.DUCE.Channel.SyncFlush()
at System.Windows.Interop.HwndTarget.UpdateWindowSettings(Boolean enableRenderTarget, Nullable`1 channelSet)
at System.Windows.Interop.HwndTarget.UpdateWindowPos(IntPtr lParam)
at System.Windows.Interop.HwndTarget.HandleMessage(WindowMessage msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Interop.HwndSource.HwndTargetFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
```

### Regression?

_No response_

### Known Workarounds

To work around the problem, it is possible to write a MarkupExtension to limit BitmapCache usage.

### Impact

_No response_

### Configuration

Reproduces on .NET 6 and .NET Framework 4.8

### Other information

The root cause is `WGXERR_WIN32ERROR` at `BaseRT.cpp:145`.
```cpp.
IFCW32(m_hrgnInvalidRegion = CreateRectRgn(0, 0, 0, 0, 0, 0));
```

Where `WGXERR_WIN32ERROR` because `CreateRectRgn` returns `NULL` due to the 10000 GDI object count limit being exceeded.

Probably to fix the problem it is possible to just ignore `BitmapCache` to avoid exceeding the limit or do what is written a few lines above:
```cpp
// Future: Do not allocate for non-mapped targets.
//
// Right now we allocate for all classes derived from CBaseRenderTarget,
// but not all of them need this functionality.
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.