diff --git a/samples/RenderDemo/MainWindow.xaml b/samples/RenderDemo/MainWindow.xaml
index e1dbd20b07..e16791b894 100644
--- a/samples/RenderDemo/MainWindow.xaml
+++ b/samples/RenderDemo/MainWindow.xaml
@@ -43,6 +43,8 @@
diff --git a/samples/RenderDemo/MainWindow.xaml.cs b/samples/RenderDemo/MainWindow.xaml.cs
index a2f3f0eac8..96e21f0d2f 100644
--- a/samples/RenderDemo/MainWindow.xaml.cs
+++ b/samples/RenderDemo/MainWindow.xaml.cs
@@ -1,6 +1,7 @@
using System;
using System.Linq.Expressions;
using Avalonia.Controls;
+using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.Rendering;
using RenderDemo.ViewModels;
@@ -37,5 +38,15 @@ namespace RenderDemo
{
AvaloniaXamlLoader.Load(this);
}
+
+ private void SetNotTransparencyMenuItem_OnClick(object? sender, RoutedEventArgs e)
+ {
+ TransparencyLevelHint = [WindowTransparencyLevel.None];
+ }
+
+ private void SetTransparencyMenuItem_OnClick(object? sender, RoutedEventArgs e)
+ {
+ TransparencyLevelHint = [WindowTransparencyLevel.Transparent];
+ }
}
}
diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs
index ceb9590564..6b83573a60 100644
--- a/src/Avalonia.Controls/TopLevel.cs
+++ b/src/Avalonia.Controls/TopLevel.cs
@@ -217,9 +217,9 @@ namespace Avalonia.Controls
_scaling = ValidateScaling(impl.RenderScaling);
_actualTransparencyLevel = PlatformImpl.TransparencyLevel;
+
-
-
+
_accessKeyHandler = TryGetService(dependencyResolver);
_inputManager = TryGetService(dependencyResolver);
diff --git a/src/Windows/Avalonia.Win32/DComposition/DirectCompositedWindow.cs b/src/Windows/Avalonia.Win32/DComposition/DirectCompositedWindow.cs
index 8935e8bcbf..de8caa85cc 100644
--- a/src/Windows/Avalonia.Win32/DComposition/DirectCompositedWindow.cs
+++ b/src/Windows/Avalonia.Win32/DComposition/DirectCompositedWindow.cs
@@ -1,6 +1,6 @@
using System;
-using System.Numerics;
using System.Threading;
+using Avalonia.Controls;
using Avalonia.OpenGL.Egl;
using Avalonia.Reactive;
using MicroCom.Runtime;
@@ -51,4 +51,13 @@ internal class DirectCompositedWindow : IDisposable
Monitor.Exit(_shared.SyncRoot);
});
}
+
+ public bool IsTransparency => _transparencyLevel != WindowTransparencyLevel.None;
+
+ public void SetTransparencyLevel(WindowTransparencyLevel transparencyLevel)
+ {
+ _transparencyLevel = transparencyLevel;
+ }
+
+ private WindowTransparencyLevel _transparencyLevel;
}
diff --git a/src/Windows/Avalonia.Win32/DComposition/DirectCompositedWindowSurface.cs b/src/Windows/Avalonia.Win32/DComposition/DirectCompositedWindowSurface.cs
index d0651e08ee..15e0f60c3c 100644
--- a/src/Windows/Avalonia.Win32/DComposition/DirectCompositedWindowSurface.cs
+++ b/src/Windows/Avalonia.Win32/DComposition/DirectCompositedWindowSurface.cs
@@ -1,9 +1,15 @@
using System;
using System.ComponentModel;
+using System.Diagnostics.CodeAnalysis;
+
+using Avalonia.Controls;
+using Avalonia.Controls.Shapes;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Win32.DirectX;
using Avalonia.Win32.Interop;
+using Avalonia.Win32.WinRT;
+
using MicroCom.Runtime;
namespace Avalonia.Win32.DComposition;
@@ -25,6 +31,7 @@ internal class DirectCompositedWindowSurface : IDirect3D11TexturePlatformSurface
{
_window ??= new DirectCompositedWindow(_info, _shared);
SetBlur(_blurEffect);
+ _window.SetTransparencyLevel(_windowTransparencyLevel);
return new DirectCompositedWindowRenderTarget(context, d3dDevice, _shared, _window);
}
@@ -43,6 +50,14 @@ internal class DirectCompositedWindowSurface : IDirect3D11TexturePlatformSurface
_blurEffect = enable;
// _window?.SetBlur(enable);
}
+
+ public void SetTransparencyLevel(WindowTransparencyLevel transparencyLevel)
+ {
+ _windowTransparencyLevel = transparencyLevel;
+ _window?.SetTransparencyLevel(transparencyLevel);
+ }
+
+ private WindowTransparencyLevel _windowTransparencyLevel;
}
internal class DirectCompositedWindowRenderTarget : IDirect3D11TextureRenderTarget
@@ -50,11 +65,13 @@ internal class DirectCompositedWindowRenderTarget : IDirect3D11TextureRenderTarg
private static readonly Guid IID_ID3D11Texture2D = Guid.Parse("6f15aaf2-d208-4e89-9ab4-489535d34f9c");
private readonly IPlatformGraphicsContext _context;
+ private readonly DirectCompositionShared _shared;
private readonly DirectCompositedWindow _window;
- private readonly IDCompositionVirtualSurface _surface;
+ private IDCompositionVirtualSurface _surface;
private bool _lost;
private PixelSize _size;
private readonly IUnknown _d3dDevice;
+ private bool _isSurfaceSupportTransparency;
public DirectCompositedWindowRenderTarget(
IPlatformGraphicsContext context, IntPtr d3dDevice,
@@ -63,13 +80,25 @@ internal class DirectCompositedWindowRenderTarget : IDirect3D11TextureRenderTarg
_d3dDevice = MicroComRuntime.CreateProxyFor(d3dDevice, false).CloneReference();
_context = context;
+ _shared = shared;
_window = window;
- using (var surfaceFactory = shared.Device.CreateSurfaceFactory(_d3dDevice))
- {
- _surface = surfaceFactory.CreateVirtualSurface(1, 1, DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM,
- DXGI_ALPHA_MODE.DXGI_ALPHA_MODE_PREMULTIPLIED);
- }
+ CreateSurface(window);
+ }
+
+ [MemberNotNull(nameof(_surface))]
+ private void CreateSurface(DirectCompositedWindow window)
+ {
+ using var surfaceFactory = _shared.Device.CreateSurfaceFactory(_d3dDevice);
+
+ const uint initialSize = 1;
+ var alphaMode = window.IsTransparency ?
+ DXGI_ALPHA_MODE.DXGI_ALPHA_MODE_PREMULTIPLIED :
+ DXGI_ALPHA_MODE.DXGI_ALPHA_MODE_IGNORE;
+ _isSurfaceSupportTransparency = window.IsTransparency;
+
+ _surface = surfaceFactory.CreateVirtualSurface(initialSize, initialSize, DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM,
+ alphaMode);
}
public void Dispose()
@@ -88,9 +117,19 @@ internal class DirectCompositedWindowRenderTarget : IDirect3D11TextureRenderTarg
bool needsEndDraw = false;
try
{
+ bool forceResize = false;
+ if (_window.IsTransparency != _isSurfaceSupportTransparency)
+ {
+ _surface.Dispose();
+
+ CreateSurface(_window);
+
+ forceResize = true;
+ }
+
var size = _window.WindowInfo.Size;
var scale = _window.WindowInfo.Scaling;
- if (_size != size)
+ if (forceResize || _size != size)
{
_surface.Resize((ushort)size.Width, (ushort)size.Height);
_size = size;
diff --git a/src/Windows/Avalonia.Win32/IBlurHost.cs b/src/Windows/Avalonia.Win32/IBlurHost.cs
index fcaf58eaac..1b5dd9c9b4 100644
--- a/src/Windows/Avalonia.Win32/IBlurHost.cs
+++ b/src/Windows/Avalonia.Win32/IBlurHost.cs
@@ -1,4 +1,6 @@
-namespace Avalonia.Win32;
+using Avalonia.Controls;
+
+namespace Avalonia.Win32;
internal enum BlurEffect
{
@@ -14,4 +16,5 @@ internal interface ICompositionEffectsSurface
bool IsBlurSupported(BlurEffect effect);
void SetBlur(BlurEffect enable);
+ void SetTransparencyLevel(WindowTransparencyLevel transparencyLevel);
}
diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs
index d720e525d3..4bade8530a 100644
--- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs
+++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs
@@ -1,6 +1,7 @@
using System;
using System.Numerics;
using System.Threading;
+using Avalonia.Controls;
using Avalonia.OpenGL.Egl;
using Avalonia.Reactive;
using MicroCom.Runtime;
@@ -112,4 +113,13 @@ internal class WinUiCompositedWindow : IDisposable
}
}
}
+
+ public bool IsTransparency => _transparencyLevel != WindowTransparencyLevel.None;
+
+ public void SetTransparencyLevel(WindowTransparencyLevel transparencyLevel)
+ {
+ _transparencyLevel = transparencyLevel;
+ }
+
+ private WindowTransparencyLevel _transparencyLevel;
}
diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs
index 2addbc6524..ee4c326fd6 100644
--- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs
+++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs
@@ -1,4 +1,6 @@
using System;
+using System.Diagnostics.CodeAnalysis;
+using Avalonia.Controls;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Win32.DirectX;
@@ -26,6 +28,7 @@ namespace Avalonia.Win32.WinRT.Composition
?.WinUICompositionBackdropCornerRadius;
_window ??= new WinUiCompositedWindow(_info, _shared, cornerRadius);
_window.SetBlur(_blurEffect);
+ _window.SetTransparencyLevel(_windowTransparencyLevel);
return new WinUiCompositedWindowRenderTarget(context, _window, d3dDevice, _shared.Compositor);
}
@@ -50,6 +53,14 @@ namespace Avalonia.Win32.WinRT.Composition
_blurEffect = enable;
_window?.SetBlur(enable);
}
+
+ public void SetTransparencyLevel(WindowTransparencyLevel transparencyLevel)
+ {
+ _windowTransparencyLevel = transparencyLevel;
+ _window?.SetTransparencyLevel(transparencyLevel);
+ }
+
+ private WindowTransparencyLevel _windowTransparencyLevel;
}
internal class WinUiCompositedWindowRenderTarget : IDirect3D11TextureRenderTarget
@@ -63,11 +74,11 @@ namespace Avalonia.Win32.WinRT.Composition
private readonly ICompositorInterop _interop;
private readonly ICompositionGraphicsDevice _compositionDevice;
private readonly ICompositionGraphicsDevice2 _compositionDevice2;
- private readonly ICompositionSurface _surface;
+ private ICompositionSurface _surface;
private PixelSize _size;
private bool _lost;
- private readonly ICompositionDrawingSurfaceInterop _surfaceInterop;
- private readonly ICompositionDrawingSurface _drawingSurface;
+ private ICompositionDrawingSurfaceInterop _surfaceInterop;
+ private ICompositionDrawingSurface _drawingSurface;
public WinUiCompositedWindowRenderTarget(IPlatformGraphicsContext context,
WinUiCompositedWindow window, IntPtr device,
@@ -83,10 +94,8 @@ namespace Avalonia.Win32.WinRT.Composition
_interop = compositor.QueryInterface();
_compositionDevice = _interop.CreateGraphicsDevice(_d3dDevice);
_compositionDevice2 = _compositionDevice.QueryInterface();
- _drawingSurface = _compositionDevice2.CreateDrawingSurface2(new UnmanagedMethods.SIZE(),
- DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied);
- _surface = _drawingSurface.QueryInterface();
- _surfaceInterop = _drawingSurface.QueryInterface();
+
+ CreateSurface(window);
}
catch
{
@@ -102,6 +111,17 @@ namespace Avalonia.Win32.WinRT.Composition
}
}
+ [MemberNotNull(nameof(_drawingSurface), nameof(_surface), nameof(_surfaceInterop))]
+ private void CreateSurface(WinUiCompositedWindow window)
+ {
+ // Do not use Premultiplied when the window is not Transparency. Because the Premultiplied AlphaMode will increase the performance loss of DWM. See https://github.com/AvaloniaUI/Avalonia/issues/20643
+ var alphaMode = window.IsTransparency ? DirectXAlphaMode.Premultiplied : DirectXAlphaMode.Ignore;
+ _drawingSurface = _compositionDevice2.CreateDrawingSurface2(new UnmanagedMethods.SIZE(),
+ DirectXPixelFormat.B8G8R8A8UIntNormalized, alphaMode);
+ _surface = _drawingSurface.QueryInterface();
+ _surfaceInterop = _drawingSurface.QueryInterface();
+ }
+
public void Dispose()
{
_surface.Dispose();
@@ -121,9 +141,25 @@ namespace Avalonia.Win32.WinRT.Composition
if (IsCorrupted)
throw new RenderTargetCorruptedException();
var transaction = _window.BeginTransaction();
+
bool needsEndDraw = false;
try
{
+ bool forceResize = false;
+ var supportTransparency = _drawingSurface.AlphaMode == DirectXAlphaMode.Premultiplied;
+ if (_window.IsTransparency != supportTransparency)
+ {
+ // Re-create the surface with correct alpha mode if the transparency support is not correct. This can happen when the transparency level is changed.
+ _surface.Dispose();
+ _surfaceInterop.Dispose();
+ _drawingSurface.Dispose();
+
+ CreateSurface(_window);
+
+ // The _drawingSurface.Size != _size, so that require force resize to update the size of surface.
+ forceResize = true;
+ }
+
var size = _window.WindowInfo.Size;
var scale = _window.WindowInfo.Scaling;
_window.ResizeIfNeeded(size);
@@ -133,7 +169,7 @@ namespace Avalonia.Win32.WinRT.Composition
UnmanagedMethods.POINT off;
try
{
- if (_size != size)
+ if (forceResize || _size != size)
{
_surfaceInterop.Resize(new UnmanagedMethods.POINT
{
diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs
index 92564d296d..cd20a5dee5 100644
--- a/src/Windows/Avalonia.Win32/WindowImpl.cs
+++ b/src/Windows/Avalonia.Win32/WindowImpl.cs
@@ -3,8 +3,10 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
+using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+
using Avalonia.Collections.Pooled;
using Avalonia.Controls;
using Avalonia.Controls.Platform;
@@ -12,22 +14,24 @@ using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Input.Raw;
using Avalonia.Input.TextInput;
+using Avalonia.Logging;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Platform.Surfaces;
using Avalonia.Platform.Storage;
+using Avalonia.Platform.Storage.FileIO;
using Avalonia.Rendering.Composition;
+using Avalonia.Threading;
using Avalonia.Win32.DirectX;
using Avalonia.Win32.Input;
using Avalonia.Win32.Interop;
using Avalonia.Win32.OpenGl;
using Avalonia.Win32.OpenGl.Angle;
using Avalonia.Win32.WinRT.Composition;
-using static Avalonia.Win32.Interop.UnmanagedMethods;
-using Avalonia.Platform.Storage.FileIO;
-using Avalonia.Threading;
+
using static Avalonia.Controls.Win32Properties;
-using Avalonia.Logging;
+using static Avalonia.Rendering.Composition.Animations.PropertySetSnapshot;
+using static Avalonia.Win32.Interop.UnmanagedMethods;
namespace Avalonia.Win32
{
@@ -180,6 +184,7 @@ namespace Avalonia.Win32
_nativeControlHost = new Win32NativeControlHost(this, !UseRedirectionBitmap);
_defaultTransparencyLevel = UseRedirectionBitmap ? WindowTransparencyLevel.None : WindowTransparencyLevel.Transparent;
_transparencyLevel = _defaultTransparencyLevel;
+ SetTransparencyLevel(_transparencyLevel);
lock (s_instances)
s_instances.Add(this);
@@ -321,6 +326,7 @@ namespace Avalonia.Win32
if (_transparencyLevel != value)
{
_transparencyLevel = value;
+ SetTransparencyLevel(value);
TransparencyLevelChanged?.Invoke(value);
}
}
@@ -372,6 +378,13 @@ namespace Avalonia.Win32
public void SetTransparencyLevelHint(IReadOnlyList transparencyLevels)
{
+ if (transparencyLevels.Count == 1 && transparencyLevels[0] == WindowTransparencyLevel.None)
+ {
+ // Explicitly disable transparency. Ignore the UseRedirectionBitmap property.
+ TransparencyLevel = WindowTransparencyLevel.None;
+ return;
+ }
+
foreach (var level in transparencyLevels)
{
if (!IsSupported(level))
@@ -506,6 +519,11 @@ namespace Avalonia.Win32
return result == 0;
}
+ private void SetTransparencyLevel(WindowTransparencyLevel transparencyLevel)
+ {
+ CompositionEffectsSurface?.SetTransparencyLevel(transparencyLevel);
+ }
+
public IPlatformRenderSurface[] Surfaces
=> _glSurface is null ?
[(IPlatformRenderSurface)Handle, _framebuffer] :