Browse Source

Merge 522625bfb5 into 658afb8717

pull/20757/merge
lindexi 21 hours ago
committed by GitHub
parent
commit
3dc794c3e1
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      samples/RenderDemo/MainWindow.xaml
  2. 11
      samples/RenderDemo/MainWindow.xaml.cs
  3. 4
      src/Avalonia.Controls/TopLevel.cs
  4. 11
      src/Windows/Avalonia.Win32/DComposition/DirectCompositedWindow.cs
  5. 53
      src/Windows/Avalonia.Win32/DComposition/DirectCompositedWindowSurface.cs
  6. 5
      src/Windows/Avalonia.Win32/IBlurHost.cs
  7. 10
      src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs
  8. 52
      src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs
  9. 26
      src/Windows/Avalonia.Win32/WindowImpl.cs

2
samples/RenderDemo/MainWindow.xaml

@ -43,6 +43,8 @@
</MenuItem> </MenuItem>
<MenuItem Header="Tests"> <MenuItem Header="Tests">
<MenuItem Command="{Binding ResizeWindow}" Header="Resize window" /> <MenuItem Command="{Binding ResizeWindow}" Header="Resize window" />
<MenuItem x:Name="SetNotTransparencyMenuItem" Header="Set window not Transparency" Click="SetNotTransparencyMenuItem_OnClick"/>
<MenuItem x:Name="SetTransparencyMenuItem" Header="Set window Transparency" Click="SetTransparencyMenuItem_OnClick"/>
</MenuItem> </MenuItem>
</MenuFlyout> </MenuFlyout>
</FlyoutBase.AttachedFlyout> </FlyoutBase.AttachedFlyout>

11
samples/RenderDemo/MainWindow.xaml.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Linq.Expressions; using System.Linq.Expressions;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Rendering; using Avalonia.Rendering;
using RenderDemo.ViewModels; using RenderDemo.ViewModels;
@ -37,5 +38,15 @@ namespace RenderDemo
{ {
AvaloniaXamlLoader.Load(this); 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];
}
} }
} }

4
src/Avalonia.Controls/TopLevel.cs

@ -217,9 +217,9 @@ namespace Avalonia.Controls
_scaling = ValidateScaling(impl.RenderScaling); _scaling = ValidateScaling(impl.RenderScaling);
_actualTransparencyLevel = PlatformImpl.TransparencyLevel; _actualTransparencyLevel = PlatformImpl.TransparencyLevel;
_accessKeyHandler = TryGetService<IAccessKeyHandler>(dependencyResolver); _accessKeyHandler = TryGetService<IAccessKeyHandler>(dependencyResolver);
_inputManager = TryGetService<IInputManager>(dependencyResolver); _inputManager = TryGetService<IInputManager>(dependencyResolver);

11
src/Windows/Avalonia.Win32/DComposition/DirectCompositedWindow.cs

@ -1,6 +1,6 @@
using System; using System;
using System.Numerics;
using System.Threading; using System.Threading;
using Avalonia.Controls;
using Avalonia.OpenGL.Egl; using Avalonia.OpenGL.Egl;
using Avalonia.Reactive; using Avalonia.Reactive;
using MicroCom.Runtime; using MicroCom.Runtime;
@ -51,4 +51,13 @@ internal class DirectCompositedWindow : IDisposable
Monitor.Exit(_shared.SyncRoot); Monitor.Exit(_shared.SyncRoot);
}); });
} }
public bool IsTransparency => _transparencyLevel != WindowTransparencyLevel.None;
public void SetTransparencyLevel(WindowTransparencyLevel transparencyLevel)
{
_transparencyLevel = transparencyLevel;
}
private WindowTransparencyLevel _transparencyLevel;
} }

53
src/Windows/Avalonia.Win32/DComposition/DirectCompositedWindowSurface.cs

@ -1,9 +1,15 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Controls;
using Avalonia.Controls.Shapes;
using Avalonia.OpenGL.Egl; using Avalonia.OpenGL.Egl;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Win32.DirectX; using Avalonia.Win32.DirectX;
using Avalonia.Win32.Interop; using Avalonia.Win32.Interop;
using Avalonia.Win32.WinRT;
using MicroCom.Runtime; using MicroCom.Runtime;
namespace Avalonia.Win32.DComposition; namespace Avalonia.Win32.DComposition;
@ -25,6 +31,7 @@ internal class DirectCompositedWindowSurface : IDirect3D11TexturePlatformSurface
{ {
_window ??= new DirectCompositedWindow(_info, _shared); _window ??= new DirectCompositedWindow(_info, _shared);
SetBlur(_blurEffect); SetBlur(_blurEffect);
_window.SetTransparencyLevel(_windowTransparencyLevel);
return new DirectCompositedWindowRenderTarget(context, d3dDevice, _shared, _window); return new DirectCompositedWindowRenderTarget(context, d3dDevice, _shared, _window);
} }
@ -43,6 +50,14 @@ internal class DirectCompositedWindowSurface : IDirect3D11TexturePlatformSurface
_blurEffect = enable; _blurEffect = enable;
// _window?.SetBlur(enable); // _window?.SetBlur(enable);
} }
public void SetTransparencyLevel(WindowTransparencyLevel transparencyLevel)
{
_windowTransparencyLevel = transparencyLevel;
_window?.SetTransparencyLevel(transparencyLevel);
}
private WindowTransparencyLevel _windowTransparencyLevel;
} }
internal class DirectCompositedWindowRenderTarget : IDirect3D11TextureRenderTarget 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 static readonly Guid IID_ID3D11Texture2D = Guid.Parse("6f15aaf2-d208-4e89-9ab4-489535d34f9c");
private readonly IPlatformGraphicsContext _context; private readonly IPlatformGraphicsContext _context;
private readonly DirectCompositionShared _shared;
private readonly DirectCompositedWindow _window; private readonly DirectCompositedWindow _window;
private readonly IDCompositionVirtualSurface _surface; private IDCompositionVirtualSurface _surface;
private bool _lost; private bool _lost;
private PixelSize _size; private PixelSize _size;
private readonly IUnknown _d3dDevice; private readonly IUnknown _d3dDevice;
private bool _isSurfaceSupportTransparency;
public DirectCompositedWindowRenderTarget( public DirectCompositedWindowRenderTarget(
IPlatformGraphicsContext context, IntPtr d3dDevice, IPlatformGraphicsContext context, IntPtr d3dDevice,
@ -63,13 +80,25 @@ internal class DirectCompositedWindowRenderTarget : IDirect3D11TextureRenderTarg
_d3dDevice = MicroComRuntime.CreateProxyFor<IUnknown>(d3dDevice, false).CloneReference(); _d3dDevice = MicroComRuntime.CreateProxyFor<IUnknown>(d3dDevice, false).CloneReference();
_context = context; _context = context;
_shared = shared;
_window = window; _window = window;
using (var surfaceFactory = shared.Device.CreateSurfaceFactory(_d3dDevice)) CreateSurface(window);
{ }
_surface = surfaceFactory.CreateVirtualSurface(1, 1, DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM,
DXGI_ALPHA_MODE.DXGI_ALPHA_MODE_PREMULTIPLIED); [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() public void Dispose()
@ -88,9 +117,19 @@ internal class DirectCompositedWindowRenderTarget : IDirect3D11TextureRenderTarg
bool needsEndDraw = false; bool needsEndDraw = false;
try try
{ {
bool forceResize = false;
if (_window.IsTransparency != _isSurfaceSupportTransparency)
{
_surface.Dispose();
CreateSurface(_window);
forceResize = true;
}
var size = _window.WindowInfo.Size; var size = _window.WindowInfo.Size;
var scale = _window.WindowInfo.Scaling; var scale = _window.WindowInfo.Scaling;
if (_size != size) if (forceResize || _size != size)
{ {
_surface.Resize((ushort)size.Width, (ushort)size.Height); _surface.Resize((ushort)size.Width, (ushort)size.Height);
_size = size; _size = size;

5
src/Windows/Avalonia.Win32/IBlurHost.cs

@ -1,4 +1,6 @@
namespace Avalonia.Win32; using Avalonia.Controls;
namespace Avalonia.Win32;
internal enum BlurEffect internal enum BlurEffect
{ {
@ -14,4 +16,5 @@ internal interface ICompositionEffectsSurface
bool IsBlurSupported(BlurEffect effect); bool IsBlurSupported(BlurEffect effect);
void SetBlur(BlurEffect enable); void SetBlur(BlurEffect enable);
void SetTransparencyLevel(WindowTransparencyLevel transparencyLevel);
} }

10
src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Numerics; using System.Numerics;
using System.Threading; using System.Threading;
using Avalonia.Controls;
using Avalonia.OpenGL.Egl; using Avalonia.OpenGL.Egl;
using Avalonia.Reactive; using Avalonia.Reactive;
using MicroCom.Runtime; 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;
} }

52
src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs

@ -1,4 +1,6 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Controls;
using Avalonia.OpenGL.Egl; using Avalonia.OpenGL.Egl;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Win32.DirectX; using Avalonia.Win32.DirectX;
@ -26,6 +28,7 @@ namespace Avalonia.Win32.WinRT.Composition
?.WinUICompositionBackdropCornerRadius; ?.WinUICompositionBackdropCornerRadius;
_window ??= new WinUiCompositedWindow(_info, _shared, cornerRadius); _window ??= new WinUiCompositedWindow(_info, _shared, cornerRadius);
_window.SetBlur(_blurEffect); _window.SetBlur(_blurEffect);
_window.SetTransparencyLevel(_windowTransparencyLevel);
return new WinUiCompositedWindowRenderTarget(context, _window, d3dDevice, _shared.Compositor); return new WinUiCompositedWindowRenderTarget(context, _window, d3dDevice, _shared.Compositor);
} }
@ -50,6 +53,14 @@ namespace Avalonia.Win32.WinRT.Composition
_blurEffect = enable; _blurEffect = enable;
_window?.SetBlur(enable); _window?.SetBlur(enable);
} }
public void SetTransparencyLevel(WindowTransparencyLevel transparencyLevel)
{
_windowTransparencyLevel = transparencyLevel;
_window?.SetTransparencyLevel(transparencyLevel);
}
private WindowTransparencyLevel _windowTransparencyLevel;
} }
internal class WinUiCompositedWindowRenderTarget : IDirect3D11TextureRenderTarget internal class WinUiCompositedWindowRenderTarget : IDirect3D11TextureRenderTarget
@ -63,11 +74,11 @@ namespace Avalonia.Win32.WinRT.Composition
private readonly ICompositorInterop _interop; private readonly ICompositorInterop _interop;
private readonly ICompositionGraphicsDevice _compositionDevice; private readonly ICompositionGraphicsDevice _compositionDevice;
private readonly ICompositionGraphicsDevice2 _compositionDevice2; private readonly ICompositionGraphicsDevice2 _compositionDevice2;
private readonly ICompositionSurface _surface; private ICompositionSurface _surface;
private PixelSize _size; private PixelSize _size;
private bool _lost; private bool _lost;
private readonly ICompositionDrawingSurfaceInterop _surfaceInterop; private ICompositionDrawingSurfaceInterop _surfaceInterop;
private readonly ICompositionDrawingSurface _drawingSurface; private ICompositionDrawingSurface _drawingSurface;
public WinUiCompositedWindowRenderTarget(IPlatformGraphicsContext context, public WinUiCompositedWindowRenderTarget(IPlatformGraphicsContext context,
WinUiCompositedWindow window, IntPtr device, WinUiCompositedWindow window, IntPtr device,
@ -83,10 +94,8 @@ namespace Avalonia.Win32.WinRT.Composition
_interop = compositor.QueryInterface<ICompositorInterop>(); _interop = compositor.QueryInterface<ICompositorInterop>();
_compositionDevice = _interop.CreateGraphicsDevice(_d3dDevice); _compositionDevice = _interop.CreateGraphicsDevice(_d3dDevice);
_compositionDevice2 = _compositionDevice.QueryInterface<ICompositionGraphicsDevice2>(); _compositionDevice2 = _compositionDevice.QueryInterface<ICompositionGraphicsDevice2>();
_drawingSurface = _compositionDevice2.CreateDrawingSurface2(new UnmanagedMethods.SIZE(),
DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied); CreateSurface(window);
_surface = _drawingSurface.QueryInterface<ICompositionSurface>();
_surfaceInterop = _drawingSurface.QueryInterface<ICompositionDrawingSurfaceInterop>();
} }
catch 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<ICompositionSurface>();
_surfaceInterop = _drawingSurface.QueryInterface<ICompositionDrawingSurfaceInterop>();
}
public void Dispose() public void Dispose()
{ {
_surface.Dispose(); _surface.Dispose();
@ -121,9 +141,25 @@ namespace Avalonia.Win32.WinRT.Composition
if (IsCorrupted) if (IsCorrupted)
throw new RenderTargetCorruptedException(); throw new RenderTargetCorruptedException();
var transaction = _window.BeginTransaction(); var transaction = _window.BeginTransaction();
bool needsEndDraw = false; bool needsEndDraw = false;
try 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 size = _window.WindowInfo.Size;
var scale = _window.WindowInfo.Scaling; var scale = _window.WindowInfo.Scaling;
_window.ResizeIfNeeded(size); _window.ResizeIfNeeded(size);
@ -133,7 +169,7 @@ namespace Avalonia.Win32.WinRT.Composition
UnmanagedMethods.POINT off; UnmanagedMethods.POINT off;
try try
{ {
if (_size != size) if (forceResize || _size != size)
{ {
_surfaceInterop.Resize(new UnmanagedMethods.POINT _surfaceInterop.Resize(new UnmanagedMethods.POINT
{ {

26
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -3,8 +3,10 @@ using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Reflection.Emit;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Avalonia.Collections.Pooled; using Avalonia.Collections.Pooled;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Platform; using Avalonia.Controls.Platform;
@ -12,22 +14,24 @@ using Avalonia.Input;
using Avalonia.Input.Platform; using Avalonia.Input.Platform;
using Avalonia.Input.Raw; using Avalonia.Input.Raw;
using Avalonia.Input.TextInput; using Avalonia.Input.TextInput;
using Avalonia.Logging;
using Avalonia.OpenGL.Egl; using Avalonia.OpenGL.Egl;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Platform.Surfaces; using Avalonia.Platform.Surfaces;
using Avalonia.Platform.Storage; using Avalonia.Platform.Storage;
using Avalonia.Platform.Storage.FileIO;
using Avalonia.Rendering.Composition; using Avalonia.Rendering.Composition;
using Avalonia.Threading;
using Avalonia.Win32.DirectX; using Avalonia.Win32.DirectX;
using Avalonia.Win32.Input; using Avalonia.Win32.Input;
using Avalonia.Win32.Interop; using Avalonia.Win32.Interop;
using Avalonia.Win32.OpenGl; using Avalonia.Win32.OpenGl;
using Avalonia.Win32.OpenGl.Angle; using Avalonia.Win32.OpenGl.Angle;
using Avalonia.Win32.WinRT.Composition; 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 static Avalonia.Controls.Win32Properties;
using Avalonia.Logging; using static Avalonia.Rendering.Composition.Animations.PropertySetSnapshot;
using static Avalonia.Win32.Interop.UnmanagedMethods;
namespace Avalonia.Win32 namespace Avalonia.Win32
{ {
@ -180,6 +184,7 @@ namespace Avalonia.Win32
_nativeControlHost = new Win32NativeControlHost(this, !UseRedirectionBitmap); _nativeControlHost = new Win32NativeControlHost(this, !UseRedirectionBitmap);
_defaultTransparencyLevel = UseRedirectionBitmap ? WindowTransparencyLevel.None : WindowTransparencyLevel.Transparent; _defaultTransparencyLevel = UseRedirectionBitmap ? WindowTransparencyLevel.None : WindowTransparencyLevel.Transparent;
_transparencyLevel = _defaultTransparencyLevel; _transparencyLevel = _defaultTransparencyLevel;
SetTransparencyLevel(_transparencyLevel);
lock (s_instances) lock (s_instances)
s_instances.Add(this); s_instances.Add(this);
@ -321,6 +326,7 @@ namespace Avalonia.Win32
if (_transparencyLevel != value) if (_transparencyLevel != value)
{ {
_transparencyLevel = value; _transparencyLevel = value;
SetTransparencyLevel(value);
TransparencyLevelChanged?.Invoke(value); TransparencyLevelChanged?.Invoke(value);
} }
} }
@ -372,6 +378,13 @@ namespace Avalonia.Win32
public void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> transparencyLevels) public void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> 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) foreach (var level in transparencyLevels)
{ {
if (!IsSupported(level)) if (!IsSupported(level))
@ -506,6 +519,11 @@ namespace Avalonia.Win32
return result == 0; return result == 0;
} }
private void SetTransparencyLevel(WindowTransparencyLevel transparencyLevel)
{
CompositionEffectsSurface?.SetTransparencyLevel(transparencyLevel);
}
public IPlatformRenderSurface[] Surfaces public IPlatformRenderSurface[] Surfaces
=> _glSurface is null ? => _glSurface is null ?
[(IPlatformRenderSurface)Handle, _framebuffer] : [(IPlatformRenderSurface)Handle, _framebuffer] :

Loading…
Cancel
Save