Browse Source

Merge 522625bfb5 into 658afb8717

pull/20757/merge
lindexi 18 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 Header="Tests">
<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>
</MenuFlyout>
</FlyoutBase.AttachedFlyout>

11
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];
}
}
}

4
src/Avalonia.Controls/TopLevel.cs

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

11
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;
}

53
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<IUnknown>(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;

5
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);
}

10
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;
}

52
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<ICompositorInterop>();
_compositionDevice = _interop.CreateGraphicsDevice(_d3dDevice);
_compositionDevice2 = _compositionDevice.QueryInterface<ICompositionGraphicsDevice2>();
_drawingSurface = _compositionDevice2.CreateDrawingSurface2(new UnmanagedMethods.SIZE(),
DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied);
_surface = _drawingSurface.QueryInterface<ICompositionSurface>();
_surfaceInterop = _drawingSurface.QueryInterface<ICompositionDrawingSurfaceInterop>();
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<ICompositionSurface>();
_surfaceInterop = _drawingSurface.QueryInterface<ICompositionDrawingSurfaceInterop>();
}
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
{

26
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<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)
{
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] :

Loading…
Cancel
Save