Browse Source

Optimize rendering performance by reduce Premultiplied AlphaMode (#20757)

* Adding TransparencyLevel property to CompositionTarget

* Try to pass the WindowTransparencyLevel to surface

* Enable change the AlphaMode in WinUI window.

* Support disable transparency explicitly;

* Adding the test demo code.

* Fix ICompositionDrawingSurfaceInterop.BeginDraw fail. Because the surface do not set size.

* Merge the same code

* Fix compile

* Add test demo code

* Put the re create surface to trycatch block.

Solve the `transaction` do not be disposed when CreateSurface exception.

* Add the dynamic Transparency alpha mode support to DirectComposited

* Revert "Adding TransparencyLevel property to CompositionTarget"

This reverts commit da0af790b1.

* Adding TransparencyLevel property to CompositionTarget

* Adding TransparencyLevel to RenderTargetSceneInfo

* Try remove the pass level

* Finish pass RenderTargetSceneInfo to create surface.

* Remove the unuse argument

* Remove the unuse code

* Bring the comments closer to the code

* Revert sort using

* Remove the unuse using

* Try fix compile error

* Remove the unuse namespace using.

* Try fix API changed

* Try fix compile

* Update api
pull/21613/head
lindexi 3 months ago
committed by GitHub
parent
commit
f655d6ffa7
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 40
      api/Avalonia.nupkg.xml
  2. 2
      samples/RenderDemo/MainWindow.xaml
  3. 11
      samples/RenderDemo/MainWindow.xaml.cs
  4. 5
      src/Avalonia.Base/Platform/IRenderTarget.cs
  5. 10
      src/Avalonia.Base/Rendering/Composition/CompositionTransparencyLevel.cs
  6. 2
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs
  7. 1
      src/Avalonia.Base/composition-schema.xml
  8. 18
      src/Avalonia.Controls/TopLevel.cs
  9. 3
      src/Avalonia.Wayland/Server/Persistent/WaylandBitmapCursor.cs
  10. 3
      src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs
  11. 3
      src/Skia/Avalonia.Skia/RenderTargetBitmapImpl.cs
  12. 1
      src/Windows/Avalonia.Win32/DComposition/DirectCompositedWindow.cs
  13. 72
      src/Windows/Avalonia.Win32/DComposition/DirectCompositedWindowSurface.cs
  14. 13
      src/Windows/Avalonia.Win32/DirectX/IDirect3D11TexturePlatformSurface.cs
  15. 10
      src/Windows/Avalonia.Win32/OpenGl/Angle/AngleD3DTextureFeature.cs
  16. 83
      src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs
  17. 7
      src/Windows/Avalonia.Win32/WindowImpl.cs
  18. 3
      tests/Avalonia.RenderTests/Media/BitmapTests.cs

40
api/Avalonia.nupkg.xml

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids -->
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
@ -19,6 +19,24 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Platform.IRenderTarget.RenderTargetSceneInfo.#ctor(Avalonia.PixelSize,System.Double,Avalonia.Size)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Platform.IRenderTarget.RenderTargetSceneInfo.#ctor(Avalonia.PixelSize,System.Double)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Platform.IRenderTarget.RenderTargetSceneInfo.Deconstruct(Avalonia.PixelSize@,System.Double@,Avalonia.Size@)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Platform.IRenderTarget.RenderTargetSceneInfo.Deconstruct(Avalonia.PixelSize@,System.Double@)</Target>
@ -49,6 +67,24 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Platform.IRenderTarget.RenderTargetSceneInfo.#ctor(Avalonia.PixelSize,System.Double,Avalonia.Size)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Platform.IRenderTarget.RenderTargetSceneInfo.#ctor(Avalonia.PixelSize,System.Double)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Platform.IRenderTarget.RenderTargetSceneInfo.Deconstruct(Avalonia.PixelSize@,System.Double@,Avalonia.Size@)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Platform.IRenderTarget.RenderTargetSceneInfo.Deconstruct(Avalonia.PixelSize@,System.Double@)</Target>
@ -61,4 +97,4 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.OpenGL.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.OpenGL.dll</Right>
</Suppression>
</Suppressions>
</Suppressions>

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

5
src/Avalonia.Base/Platform/IRenderTarget.cs

@ -1,5 +1,6 @@
using System;
using Avalonia.Metadata;
using Avalonia.Rendering.Composition;
namespace Avalonia.Platform
{
@ -32,9 +33,9 @@ namespace Avalonia.Platform
/// </summary>
PlatformRenderTargetState PlatformRenderTargetState => PlatformRenderTargetState.Ready;
public record struct RenderTargetSceneInfo(PixelSize Size, double Scaling, Size LogicalSize)
public record struct RenderTargetSceneInfo(PixelSize Size, double Scaling, Size LogicalSize, CompositionTransparencyLevel TransparencyLevel)
{
public RenderTargetSceneInfo(PixelSize size, double scaling) : this(size, scaling, size.ToSize(scaling))
public RenderTargetSceneInfo(PixelSize size, double scaling, CompositionTransparencyLevel transparencyLevel) : this(size, scaling, size.ToSize(scaling), transparencyLevel)
{
}
}

10
src/Avalonia.Base/Rendering/Composition/CompositionTransparencyLevel.cs

@ -0,0 +1,10 @@
namespace Avalonia.Rendering.Composition;
public enum CompositionTransparencyLevel : byte
{
None = 0,
Transparent = 1,
Blur = 2,
AcrylicBlur = 3,
Mica = 4
}

2
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs

@ -205,7 +205,7 @@ namespace Avalonia.Rendering.Composition.Server
try
{
renderTargetContext =
_renderTarget.CreateDrawingContext(new(PixelSize, Scaling, Size), out properties);
_renderTarget.CreateDrawingContext(new(PixelSize, Scaling, Size, TransparencyLevel), out properties);
}
catch (RenderTargetNotReadyException)
{

1
src/Avalonia.Base/composition-schema.xml

@ -59,6 +59,7 @@
<Property Name="LastLayoutPassTiming" Type="LayoutPassTiming" Internal="true"/>
<Property Name="Scaling" Type="double"/>
<Property Name="Size" Type="Size" />
<Property Name="TransparencyLevel" Type="CompositionTransparencyLevel" />
</Object>
<KeyFrameAnimation Name="Scalar" Type="float"/>
<KeyFrameAnimation Name="Double" Type="double"/>

18
src/Avalonia.Controls/TopLevel.cs

@ -218,7 +218,8 @@ namespace Avalonia.Controls
_scaling = LayoutHelper.ValidateScaling(impl.RenderScaling);
_actualTransparencyLevel = PlatformImpl.TransparencyLevel;
_source.Renderer.CompositionTarget.TransparencyLevel =
ToCompositionTransparencyLevel(_actualTransparencyLevel);
_accessKeyHandler = TryGetService<IAccessKeyHandler>(dependencyResolver);
@ -731,6 +732,8 @@ namespace Avalonia.Controls
}
ActualTransparencyLevel = transparencyLevel;
Renderer.CompositionTarget.TransparencyLevel =
ToCompositionTransparencyLevel(transparencyLevel);
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
@ -833,5 +836,18 @@ namespace Avalonia.Controls
{
// Do nothing becuase TopLevel should't apply MirrorTransform on himself.
}
private static CompositionTransparencyLevel ToCompositionTransparencyLevel(WindowTransparencyLevel level)
{
if (level == WindowTransparencyLevel.Transparent)
return CompositionTransparencyLevel.Transparent;
if (level == WindowTransparencyLevel.Blur)
return CompositionTransparencyLevel.Blur;
if (level == WindowTransparencyLevel.AcrylicBlur)
return CompositionTransparencyLevel.AcrylicBlur;
if (level == WindowTransparencyLevel.Mica)
return CompositionTransparencyLevel.Mica;
return CompositionTransparencyLevel.None;
}
}
}

3
src/Avalonia.Wayland/Server/Persistent/WaylandBitmapCursor.cs

@ -4,6 +4,7 @@ using System.Linq;
using System.Runtime.InteropServices;
using Avalonia;
using Avalonia.Platform;
using Avalonia.Rendering.Composition;
using Avalonia.Wayland.Server.Interop;
using Avalonia.Wayland.Server.Transient;
using Avalonia.Wayland.Server.Transient.Rendering;
@ -75,7 +76,7 @@ sealed class WaylandBitmapCursor : WaylandCursor, IPersistentWaylandObject, IWay
var framebuffer = new WaylandFramebuffer(this);
using var renderTarget = framebuffer.CreateFramebufferRenderTarget();
using var locked = renderTarget.Lock(new IRenderTarget.RenderTargetSceneInfo(_size, 1), out _);
using var locked = renderTarget.Lock(new IRenderTarget.RenderTargetSceneInfo(_size, 1, CompositionTransparencyLevel.None), out _);
// The locked framebuffer is Bgra8888 premultiplied with stride == Width * 4, matching the
// packed pixel data we captured on the UI thread. Disposing the lock attaches + commits.
Marshal.Copy(_pixels, 0, locked.Address, _pixels.Length);

3
src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs

@ -8,6 +8,7 @@ using Avalonia.OpenGL;
using Avalonia.OpenGL.Egl;
using Avalonia.OpenGL.Surfaces;
using Avalonia.Platform;
using Avalonia.Rendering.Composition;
using static Avalonia.LinuxFramebuffer.NativeUnsafeMethods;
using static Avalonia.LinuxFramebuffer.Output.LibDrm;
@ -377,7 +378,7 @@ namespace Avalonia.LinuxFramebuffer.Output
{
//Go through two cycles of buffer swapping (there are render artifacts otherwise)
for (var c = 0; c < 2; c++)
using (CreateGlRenderTarget().BeginDraw(new IRenderTarget.RenderTargetSceneInfo(PixelSize, 1)))
using (CreateGlRenderTarget().BeginDraw(new IRenderTarget.RenderTargetSceneInfo(PixelSize, 1, CompositionTransparencyLevel.None)))
{
_deferredContext.GlInterface.ClearColor(initialBufferSwappingColorR, initialBufferSwappingColorG,
initialBufferSwappingColorB, initialBufferSwappingColorA);

3
src/Skia/Avalonia.Skia/RenderTargetBitmapImpl.cs

@ -1,5 +1,6 @@
using Avalonia.Platform.Surfaces;
using Avalonia.Platform;
using Avalonia.Rendering.Composition;
using SkiaSharp;
namespace Avalonia.Skia;
@ -20,7 +21,7 @@ internal class RenderTargetBitmapImpl : WriteableBitmapImpl,
public IDrawingContextImpl CreateDrawingContext()
{
return _renderTarget.CreateDrawingContext(new IRenderTarget.RenderTargetSceneInfo(
PixelSize, Dpi.X / 96.0), out _);
PixelSize, Dpi.X / 96.0, CompositionTransparencyLevel.None), out _);
}

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

@ -1,5 +1,4 @@
using System;
using System.Numerics;
using System.Threading;
using Avalonia.OpenGL.Egl;
using Avalonia.Reactive;

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

@ -1,14 +1,17 @@
using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Rendering.Composition;
using Avalonia.Win32.DirectX;
using Avalonia.Win32.Interop;
using MicroCom.Runtime;
namespace Avalonia.Win32.DComposition;
internal class DirectCompositedWindowSurface : IDirect3D11TexturePlatformSurface, IDisposable, ICompositionEffectsSurface
internal class DirectCompositedWindowSurface : IDirect3D11TexturePlatformSurface, IDirect3D11TexturePlatformSurface2, IDisposable, ICompositionEffectsSurface
{
private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info;
private readonly DirectCompositionShared _shared;
@ -21,7 +24,12 @@ internal class DirectCompositedWindowSurface : IDirect3D11TexturePlatformSurface
_info = info;
}
public IDirect3D11TextureRenderTarget CreateRenderTarget(IPlatformGraphicsContext context, IntPtr d3dDevice)
IDirect3D11TextureRenderTarget IDirect3D11TexturePlatformSurface.CreateRenderTarget(IPlatformGraphicsContext context, IntPtr d3dDevice)
{
return (IDirect3D11TextureRenderTarget) CreateRenderTarget(context, d3dDevice);
}
public IDirect3D11TextureRenderTarget2 CreateRenderTarget(IPlatformGraphicsContext context, IntPtr d3dDevice)
{
_window ??= new DirectCompositedWindow(_info, _shared);
SetBlur(_blurEffect);
@ -45,16 +53,18 @@ internal class DirectCompositedWindowSurface : IDirect3D11TexturePlatformSurface
}
}
internal class DirectCompositedWindowRenderTarget : IDirect3D11TextureRenderTarget
internal class DirectCompositedWindowRenderTarget : IDirect3D11TextureRenderTarget, IDirect3D11TextureRenderTarget2
{
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,24 +73,44 @@ 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);
}
[MemberNotNull(nameof(_surface))]
private void CreateSurface(in IRenderTarget.RenderTargetSceneInfo sceneInfo)
{
using var surfaceFactory = _shared.Device.CreateSurfaceFactory(_d3dDevice);
bool isTransparency = sceneInfo.TransparencyLevel != CompositionTransparencyLevel.None;
var surfaceSize = sceneInfo.Size;
var alphaMode = isTransparency ?
DXGI_ALPHA_MODE.DXGI_ALPHA_MODE_PREMULTIPLIED :
DXGI_ALPHA_MODE.DXGI_ALPHA_MODE_IGNORE;
_surface = surfaceFactory.CreateVirtualSurface((uint)surfaceSize.Width, (uint)surfaceSize.Height, DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM, alphaMode);
_isSurfaceSupportTransparency = isTransparency;
_size = surfaceSize;
}
public void Dispose()
{
_surface.Dispose();
_surface?.Dispose();
_d3dDevice.Dispose();
}
public PlatformRenderTargetState State => _context.IsLost || _lost ? PlatformRenderTargetState.Corrupted : PlatformRenderTargetState.Ready;
public unsafe IDirect3D11TextureRenderTargetRenderSession BeginDraw()
IDirect3D11TextureRenderTargetRenderSession IDirect3D11TextureRenderTarget.BeginDraw()
{
var fallbackSceneInfo = new IRenderTarget.RenderTargetSceneInfo(_window.WindowInfo.Size,
_window.WindowInfo.Scaling, CompositionTransparencyLevel.None);
return BeginDraw(fallbackSceneInfo);
}
public unsafe IDirect3D11TextureRenderTargetRenderSession BeginDraw(IRenderTarget.RenderTargetSceneInfo sceneInfo)
{
if (State.IsCorrupted)
throw new RenderTargetCorruptedException();
@ -88,11 +118,19 @@ internal class DirectCompositedWindowRenderTarget : IDirect3D11TextureRenderTarg
bool needsEndDraw = false;
try
{
var size = _window.WindowInfo.Size;
var scale = _window.WindowInfo.Scaling;
bool isTransparency = sceneInfo.TransparencyLevel != CompositionTransparencyLevel.None;
if (_surface is null || isTransparency != _isSurfaceSupportTransparency)
{
_surface?.Dispose();
CreateSurface(in sceneInfo);
}
var size = sceneInfo.Size;
var scale = sceneInfo.Scaling;
if (_size != size)
{
_surface.Resize((ushort)size.Width, (ushort)size.Height);
_surface.Resize((uint)size.Width, (uint)size.Height);
_size = size;
}
@ -125,7 +163,7 @@ internal class DirectCompositedWindowRenderTarget : IDirect3D11TextureRenderTarg
if (transaction != null)
{
if (needsEndDraw)
_surface.EndDraw();
_surface?.EndDraw();
transaction.Dispose();
}
}

13
src/Windows/Avalonia.Win32/DirectX/IDirect3D11TexturePlatformSurface.cs

@ -1,4 +1,6 @@
using System;
using Avalonia.Metadata;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Surfaces;
using Avalonia.Platform;
@ -11,6 +13,11 @@ public interface IDirect3D11TexturePlatformSurface : IPlatformRenderSurface
public IDirect3D11TextureRenderTarget CreateRenderTarget(IPlatformGraphicsContext graphicsContext, IntPtr d3dDevice);
}
[PrivateApi]
public interface IDirect3D11TexturePlatformSurface2 : IPlatformRenderSurface
{
IDirect3D11TextureRenderTarget2 CreateRenderTarget(IPlatformGraphicsContext graphicsContext, IntPtr d3dDevice);
}
public interface IDirect3D11TextureRenderTarget : IPlatformRenderSurfaceRenderTarget, IDisposable
@ -18,6 +25,12 @@ public interface IDirect3D11TextureRenderTarget : IPlatformRenderSurfaceRenderTa
IDirect3D11TextureRenderTargetRenderSession BeginDraw();
}
[PrivateApi]
public interface IDirect3D11TextureRenderTarget2 : IPlatformRenderSurfaceRenderTarget, IDisposable
{
IDirect3D11TextureRenderTargetRenderSession BeginDraw(IRenderTarget.RenderTargetSceneInfo sceneInfo);
}
public interface IDirect3D11TextureRenderTargetRenderSession : IDisposable
{
public IntPtr D3D11Texture2D { get; }

10
src/Windows/Avalonia.Win32/OpenGl/Angle/AngleD3DTextureFeature.cs

@ -14,16 +14,16 @@ internal class AngleD3DTextureFeature : IGlPlatformSurfaceRenderTargetFactory
context is EglContext
{
Display: AngleWin32EglDisplay { PlatformApi: AngleOptions.PlatformApi.DirectX11 }
} && surface is IDirect3D11TexturePlatformSurface;
} && surface is IDirect3D11TexturePlatformSurface2;
private class RenderTargetWrapper : EglPlatformSurfaceRenderTargetBase
{
private readonly AngleWin32EglDisplay _angle;
private readonly IDirect3D11TextureRenderTarget _target;
private readonly IDirect3D11TextureRenderTarget2 _target;
public RenderTargetWrapper(EglContext context,
AngleWin32EglDisplay angle,
IDirect3D11TextureRenderTarget target) : base(context)
IDirect3D11TextureRenderTarget2 target) : base(context)
{
_angle = angle;
_target = target;
@ -40,7 +40,7 @@ internal class AngleD3DTextureFeature : IGlPlatformSurfaceRenderTargetFactory
{
try
{
session = _target.BeginDraw();
session = _target.BeginDraw(sceneInfo);
}
catch (RenderTargetCorruptedException e)
{
@ -91,7 +91,7 @@ internal class AngleD3DTextureFeature : IGlPlatformSurfaceRenderTargetFactory
{
var ctx = (EglContext)context;
var angle = (AngleWin32EglDisplay)ctx.Display;
var textureSurface = (IDirect3D11TexturePlatformSurface)surface;
var textureSurface = (IDirect3D11TexturePlatformSurface2)surface;
try
{
var target = textureSurface.CreateRenderTarget(context, angle.GetDirect3DDevice());

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

@ -1,13 +1,15 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Rendering.Composition;
using Avalonia.Win32.DirectX;
using Avalonia.Win32.Interop;
using MicroCom.Runtime;
namespace Avalonia.Win32.WinRT.Composition
{
internal class WinUiCompositedWindowSurface : IDirect3D11TexturePlatformSurface, IDisposable, ICompositionEffectsSurface
internal class WinUiCompositedWindowSurface : IDirect3D11TexturePlatformSurface, IDirect3D11TexturePlatformSurface2, IDisposable, ICompositionEffectsSurface
{
private readonly WinUiCompositionShared _shared;
private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info;
@ -20,7 +22,12 @@ namespace Avalonia.Win32.WinRT.Composition
_info = info;
}
public IDirect3D11TextureRenderTarget CreateRenderTarget(IPlatformGraphicsContext context, IntPtr d3dDevice)
IDirect3D11TextureRenderTarget IDirect3D11TexturePlatformSurface.CreateRenderTarget(IPlatformGraphicsContext context, IntPtr d3dDevice)
{
return (IDirect3D11TextureRenderTarget) CreateRenderTarget(context, d3dDevice);
}
public IDirect3D11TextureRenderTarget2 CreateRenderTarget(IPlatformGraphicsContext context, IntPtr d3dDevice)
{
var cornerRadius = AvaloniaLocator.Current.GetService<Win32PlatformOptions>()
?.WinUICompositionBackdropCornerRadius;
@ -52,7 +59,7 @@ namespace Avalonia.Win32.WinRT.Composition
}
}
internal class WinUiCompositedWindowRenderTarget : IDirect3D11TextureRenderTarget
internal class WinUiCompositedWindowRenderTarget : IDirect3D11TextureRenderTarget, IDirect3D11TextureRenderTarget2
{
private static readonly Guid IID_ID3D11Texture2D = Guid.Parse("6f15aaf2-d208-4e89-9ab4-489535d34f9c");
@ -63,11 +70,12 @@ 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 bool _isSurfaceSupportTransparency;
private ICompositionDrawingSurfaceInterop? _surfaceInterop;
private ICompositionDrawingSurface? _drawingSurface;
public WinUiCompositedWindowRenderTarget(IPlatformGraphicsContext context,
WinUiCompositedWindow window, IntPtr device,
@ -83,16 +91,9 @@ 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>();
}
catch
{
_surface?.Dispose();
_surfaceInterop?.Dispose();
_drawingSurface?.Dispose();
_compositionDevice2?.Dispose();
_compositionDevice?.Dispose();
_interop?.Dispose();
@ -104,9 +105,9 @@ namespace Avalonia.Win32.WinRT.Composition
public void Dispose()
{
_surface.Dispose();
_surfaceInterop.Dispose();
_drawingSurface.Dispose();
_surface?.Dispose();
_surfaceInterop?.Dispose();
_drawingSurface?.Dispose();
_compositionDevice2.Dispose();
_compositionDevice.Dispose();
_interop.Dispose();
@ -114,19 +115,61 @@ namespace Avalonia.Win32.WinRT.Composition
_d3dDevice.Dispose();
}
[MemberNotNull(nameof(_drawingSurface), nameof(_surface), nameof(_surfaceInterop))]
private void CreateSurface(in IRenderTarget.RenderTargetSceneInfo sceneInfo)
{
bool isTransparency = sceneInfo.TransparencyLevel != CompositionTransparencyLevel.None;
var surfaceSize = sceneInfo.Size;
// 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 = isTransparency ? DirectXAlphaMode.Premultiplied : DirectXAlphaMode.Ignore;
_drawingSurface = _compositionDevice2.CreateDrawingSurface2(new UnmanagedMethods.SIZE()
{
X = surfaceSize.Width,
Y = surfaceSize.Height,
},
DirectXPixelFormat.B8G8R8A8UIntNormalized, alphaMode);
_surface = _drawingSurface.QueryInterface<ICompositionSurface>();
_surfaceInterop = _drawingSurface.QueryInterface<ICompositionDrawingSurfaceInterop>();
_isSurfaceSupportTransparency = isTransparency;
_size = surfaceSize;
}
public PlatformRenderTargetState State =>
_context.IsLost || _lost ? PlatformRenderTargetState.Corrupted : PlatformRenderTargetState.Ready;
public unsafe IDirect3D11TextureRenderTargetRenderSession BeginDraw()
IDirect3D11TextureRenderTargetRenderSession IDirect3D11TextureRenderTarget.BeginDraw()
{
var fallbackSceneInfo = new IRenderTarget.RenderTargetSceneInfo(_window.WindowInfo.Size,
_window.WindowInfo.Scaling, CompositionTransparencyLevel.None);
return BeginDraw(fallbackSceneInfo);
}
public unsafe IDirect3D11TextureRenderTargetRenderSession BeginDraw(
IRenderTarget.RenderTargetSceneInfo sceneInfo)
{
if (State.IsCorrupted)
throw new RenderTargetCorruptedException();
var transaction = _window.BeginTransaction();
bool needsEndDraw = false;
try
{
var size = _window.WindowInfo.Size;
var scale = _window.WindowInfo.Scaling;
bool isTransparency = sceneInfo.TransparencyLevel != CompositionTransparencyLevel.None;
if (_surface is null || _surfaceInterop is null || _drawingSurface is null || _isSurfaceSupportTransparency != isTransparency)
{
// 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(in sceneInfo);
}
var size = sceneInfo.Size;
var scale = sceneInfo.Scaling;
_window.ResizeIfNeeded(size);
_window.SetSurface(_surface);
@ -165,7 +208,7 @@ namespace Avalonia.Win32.WinRT.Composition
if (transaction != null)
{
if (needsEndDraw)
_surfaceInterop.EndDraw();
_surfaceInterop?.EndDraw();
transaction.Dispose();
}
}

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

@ -373,6 +373,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))

3
tests/Avalonia.RenderTests/Media/BitmapTests.cs

@ -8,6 +8,7 @@ using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
using Avalonia.Platform.Surfaces;
using Avalonia.Rendering.Composition;
using Xunit;
using Path = System.IO.Path;
@ -71,7 +72,7 @@ namespace Avalonia.Skia.RenderTests
var r = AvaloniaLocator.Current.GetRequiredService<IPlatformRenderInterface>();
using(var cpuContext = r.CreateBackendContext(null))
using (var target = cpuContext.CreateRenderTarget(new IPlatformRenderSurface[] { fb }))
using (var ctx = target.CreateDrawingContext(new IRenderTarget.RenderTargetSceneInfo(fb.Size, 1), out _))
using (var ctx = target.CreateDrawingContext(new IRenderTarget.RenderTargetSceneInfo(fb.Size, 1, CompositionTransparencyLevel.None), out _))
{
ctx.Clear(Colors.Transparent);
ctx.PushOpacity(0.8, new Rect(0, 0, 80, 80));

Loading…
Cancel
Save