diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
index 9b86154043..a7cca5b0f3 100644
--- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
+++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
@@ -1627,7 +1627,7 @@ namespace Avalonia.Win32.Interop
public static extern bool wglDeleteContext(IntPtr context);
- [DllImport("opengl32.dll")]
+ [DllImport("opengl32.dll", SetLastError = true)]
public static extern bool wglMakeCurrent(IntPtr hdc, IntPtr context);
[DllImport("opengl32.dll")]
diff --git a/src/Windows/Avalonia.Win32/OpenGl/WglContext.cs b/src/Windows/Avalonia.Win32/OpenGl/WglContext.cs
index da8780d413..a2c0d9203d 100644
--- a/src/Windows/Avalonia.Win32/OpenGl/WglContext.cs
+++ b/src/Windows/Avalonia.Win32/OpenGl/WglContext.cs
@@ -46,7 +46,7 @@ namespace Avalonia.Win32.OpenGl
public void Dispose()
{
wglDeleteContext(_context);
- ReleaseDC(_hWnd, _dc);
+ WglDCManager.ReleaseDC(_hWnd, _dc);
DestroyWindow(_hWnd);
IsLost = true;
}
@@ -72,7 +72,7 @@ namespace Avalonia.Win32.OpenGl
public IntPtr CreateConfiguredDeviceContext(IntPtr hWnd)
{
- var dc = GetDC(hWnd);
+ var dc = WglDCManager.GetDC(hWnd);
var fmt = _formatDescriptor;
SetPixelFormat(dc, _pixelFormat, ref fmt);
return dc;
diff --git a/src/Windows/Avalonia.Win32/OpenGl/WglDCManager.cs b/src/Windows/Avalonia.Win32/OpenGl/WglDCManager.cs
new file mode 100644
index 0000000000..2698c8eb5f
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/OpenGl/WglDCManager.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Avalonia.Win32.Interop;
+
+namespace Avalonia.Win32.OpenGl;
+
+///
+/// 1) ReleaseDC can only happen from the same thread that has called GetDC
+/// 2) When thread exits all of its HDCs are getting destroyed
+/// 3) We need to create OpenGL render targets from thread pool threads
+///
+/// So this class hosts a dedicated thread for managing HDCs for OpenGL
+///
+
+internal class WglDCManager
+{
+ class GetDCOp
+ {
+ public IntPtr Window;
+ public TaskCompletionSource Result;
+ }
+
+ class ReleaseDCOp
+ {
+ public IntPtr Window;
+ public IntPtr DC;
+ public TaskCompletionSource