Add AlphaFormat to ILockedFramebuffer (#20556)

* Add AlphaFormat to ILockedFramebuffer

* Update API suppressions
This commit is contained in:
Julien Lebosquain
2026-01-30 09:55:40 +00:00
committed by GitHub
parent 3394815603
commit 4c3c9aa99f
26 changed files with 144 additions and 58 deletions
+72
View File
@@ -19,6 +19,12 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Platform.IReadableBitmapWithAlphaImpl</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Utilities.StringTokenizer</Target>
@@ -55,6 +61,12 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Platform.IReadableBitmapWithAlphaImpl</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Utilities.StringTokenizer</Target>
@@ -127,6 +139,12 @@
<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.Media.Imaging.Bitmap.CopyPixels(Avalonia.Platform.ILockedFramebuffer,Avalonia.Platform.AlphaFormat)</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.Media.StreamGeometryContext.ArcTo(Avalonia.Point,Avalonia.Size,System.Double,System.Boolean,Avalonia.Media.SweepDirection)</Target>
@@ -229,6 +247,12 @@
<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.LockedFramebuffer.#ctor(System.IntPtr,Avalonia.PixelSize,System.Int32,Avalonia.Vector,Avalonia.Platform.PixelFormat,System.Action)</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.Visuals.Platform.PathGeometryContext.ArcTo(Avalonia.Point,Avalonia.Size,System.Double,System.Boolean,Avalonia.Media.SweepDirection)</Target>
@@ -481,6 +505,12 @@
<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.Media.Imaging.Bitmap.CopyPixels(Avalonia.Platform.ILockedFramebuffer,Avalonia.Platform.AlphaFormat)</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.Media.StreamGeometryContext.ArcTo(Avalonia.Point,Avalonia.Size,System.Double,System.Boolean,Avalonia.Media.SweepDirection)</Target>
@@ -583,6 +613,12 @@
<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.LockedFramebuffer.#ctor(System.IntPtr,Avalonia.PixelSize,System.Int32,Avalonia.Vector,Avalonia.Platform.PixelFormat,System.Action)</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.Visuals.Platform.PathGeometryContext.ArcTo(Avalonia.Point,Avalonia.Size,System.Double,System.Boolean,Avalonia.Media.SweepDirection)</Target>
@@ -853,6 +889,18 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>P:Avalonia.Platform.ILockedFramebuffer.AlphaFormat</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>P:Avalonia.Platform.IReadableBitmapImpl.AlphaFormat</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Input.Platform.IClipboard.SetDataAsync(Avalonia.Input.IAsyncDataTransfer)</Target>
@@ -1003,6 +1051,18 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>P:Avalonia.Platform.ILockedFramebuffer.AlphaFormat</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>P:Avalonia.Platform.IReadableBitmapImpl.AlphaFormat</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.OpenGL.IGlExternalSemaphore.SignalTimelineSemaphore(Avalonia.OpenGL.IGlExternalImageTexture,System.UInt64)</Target>
@@ -1087,12 +1147,24 @@
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Platform.IWriteableBitmapImpl</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Media.StreamGeometryContext</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Platform.IWriteableBitmapImpl</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0009</DiagnosticId>
<Target>T:Avalonia.Platform.Screen</Target>
@@ -25,10 +25,10 @@ namespace Avalonia.Android.Platform.SkiaPlatform
Size = new PixelSize(rc.right, rc.bottom);
ANativeWindow_lock(_window, &buffer, &rc);
Format = buffer.format == AndroidPixelFormat.WINDOW_FORMAT_RGB_565
? PixelFormat.Rgb565 : PixelFormat.Rgba8888;
(Format, AlphaFormat, RowBytes) = buffer.format == AndroidPixelFormat.WINDOW_FORMAT_RGB_565 ?
(PixelFormat.Rgb565, AlphaFormat.Opaque, buffer.stride * 2) :
(PixelFormat.Rgba8888, AlphaFormat.Premul, buffer.stride * 4);
RowBytes = buffer.stride * (Format == PixelFormat.Rgb565 ? 2 : 4);
Address = buffer.bits;
Dpi = new Vector(96, 96) * scaling;
@@ -46,6 +46,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public int RowBytes { get; }
public Vector Dpi { get; }
public PixelFormat Format { get; }
public AlphaFormat AlphaFormat { get; }
[DllImport("android")]
internal static extern IntPtr ANativeWindow_fromSurface(IntPtr jniEnv, IntPtr handle);
+6 -8
View File
@@ -1,5 +1,4 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Runtime.CompilerServices;
using Avalonia.Platform;
@@ -177,7 +176,7 @@ namespace Avalonia.Media.Imaging
public virtual PixelFormat? Format => (PlatformImpl.Item as IReadableBitmapImpl)?.Format;
public virtual AlphaFormat? AlphaFormat => (PlatformImpl.Item as IReadableBitmapWithAlphaImpl)?.AlphaFormat;
public virtual AlphaFormat? AlphaFormat => (PlatformImpl.Item as IReadableBitmapImpl)?.AlphaFormat;
private protected unsafe void CopyPixelsCore(PixelRect sourceRect, IntPtr buffer, int bufferSize, int stride,
ILockedFramebuffer fb)
@@ -237,16 +236,15 @@ namespace Avalonia.Media.Imaging
/// Copies pixels to the target buffer and transcodes the pixel and alpha format if needed.
/// </summary>
/// <param name="buffer">The target buffer.</param>
/// <param name="alphaFormat">The alpha format.</param>
/// <exception cref="NotSupportedException"></exception>
public void CopyPixels(ILockedFramebuffer buffer, AlphaFormat alphaFormat)
public void CopyPixels(ILockedFramebuffer buffer)
{
if (PlatformImpl.Item is not IReadableBitmapWithAlphaImpl readable || readable.Format == null || readable.AlphaFormat == null)
if (PlatformImpl.Item is not IReadableBitmapImpl readable || readable.Format == null || readable.AlphaFormat == null)
{
throw new NotSupportedException("CopyPixels is not supported for this bitmap type");
}
if (buffer.Format != readable.Format || alphaFormat != readable.AlphaFormat)
if (buffer.Format != readable.Format || buffer.AlphaFormat != readable.AlphaFormat)
{
using (var fb = readable.Lock())
{
@@ -255,11 +253,11 @@ namespace Avalonia.Media.Imaging
fb.Size,
fb.RowBytes,
fb.Format,
readable.AlphaFormat.Value,
fb.AlphaFormat,
buffer.Address,
buffer.RowBytes,
buffer.Format,
alphaFormat);
buffer.AlphaFormat);
}
}
else
@@ -71,10 +71,10 @@ namespace Avalonia.Media.Imaging
return new LockedFramebuffer(_pixelFormatMemory.Address, _pixelFormatMemory.Size,
_pixelFormatMemory.RowBytes,
Dpi, _pixelFormatMemory.Format, () =>
Dpi, _pixelFormatMemory.Format, _pixelFormatMemory.AlphaFormat, () =>
{
using var inner = ((IWriteableBitmapImpl)PlatformImpl.Item).Lock();
_pixelFormatMemory.CopyToRgba(Platform.AlphaFormat.Unpremul, inner.Address, inner.RowBytes);
_pixelFormatMemory.CopyToRgba(inner.AlphaFormat, inner.Address, inner.RowBytes);
});
}
@@ -29,6 +29,9 @@ namespace Avalonia.Platform
/// </summary>
PixelFormat Format { get; }
//TODO12: Add AlphaFormat
/// <summary>
/// Gets the alpha format.
/// </summary>
AlphaFormat AlphaFormat { get; }
}
}
@@ -2,15 +2,10 @@ using Avalonia.Metadata;
namespace Avalonia.Platform;
public interface IReadableBitmapImpl
[PrivateApi]
public interface IReadableBitmapImpl : IBitmapImpl
{
PixelFormat? Format { get; }
AlphaFormat? AlphaFormat { get; }
ILockedFramebuffer Lock();
}
//TODO12: Remove me once we can change IReadableBitmapImpl
[Unstable]
public interface IReadableBitmapWithAlphaImpl : IReadableBitmapImpl
{
AlphaFormat? AlphaFormat { get; }
}
@@ -5,8 +5,8 @@ namespace Avalonia.Platform
/// <summary>
/// Defines the platform-specific interface for a <see cref="Avalonia.Media.Imaging.WriteableBitmap"/>.
/// </summary>
[Unstable]
public interface IWriteableBitmapImpl : IBitmapImpl, IReadableBitmapWithAlphaImpl
[PrivateApi]
public interface IWriteableBitmapImpl : IBitmapImpl, IReadableBitmapImpl
{
}
}
@@ -7,7 +7,7 @@ namespace Avalonia.Platform
private readonly Action? _onDispose;
public LockedFramebuffer(IntPtr address, PixelSize size, int rowBytes, Vector dpi, PixelFormat format,
Action? onDispose)
AlphaFormat alphaFormat, Action? onDispose)
{
_onDispose = onDispose;
Address = address;
@@ -15,6 +15,7 @@ namespace Avalonia.Platform
RowBytes = rowBytes;
Dpi = dpi;
Format = format;
AlphaFormat = alphaFormat;
}
public IntPtr Address { get; }
@@ -22,6 +23,7 @@ namespace Avalonia.Platform
public int RowBytes { get; }
public Vector Dpi { get; }
public PixelFormat Format { get; }
public AlphaFormat AlphaFormat { get; }
public void Dispose()
{
@@ -1,6 +1,4 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.Metadata;
using Avalonia.Platform.Internal;
namespace Avalonia.Platform;
@@ -10,6 +8,7 @@ internal class RetainedFramebuffer : IDisposable
public PixelSize Size { get; }
public int RowBytes { get; }
public PixelFormat Format { get; }
public AlphaFormat AlphaFormat { get; }
public IntPtr Address => _blob?.Address ?? throw new ObjectDisposedException(nameof(RetainedFramebuffer));
private UnmanagedBlob? _blob;
@@ -17,13 +16,13 @@ internal class RetainedFramebuffer : IDisposable
? format
: throw new ArgumentOutOfRangeException(nameof(format));
public RetainedFramebuffer(PixelSize size, PixelFormat format) : this(size, ValidateKnownFormat(format),
format.BitsPerPixel / 8 * size.Width)
public RetainedFramebuffer(PixelSize size, PixelFormat format, AlphaFormat alphaFormat)
: this(size, ValidateKnownFormat(format), alphaFormat, format.BitsPerPixel / 8 * size.Width)
{
}
public RetainedFramebuffer(PixelSize size, PixelFormat format, int rowBytes)
public RetainedFramebuffer(PixelSize size, PixelFormat format, AlphaFormat alphaFormat, int rowBytes)
{
if (size.Width <= 0 || size.Height <= 0)
throw new ArgumentOutOfRangeException(nameof(size));
@@ -32,6 +31,7 @@ internal class RetainedFramebuffer : IDisposable
Size = size;
RowBytes = rowBytes;
Format = format;
AlphaFormat = alphaFormat;
_blob = new UnmanagedBlob(RowBytes * size.Height);
}
@@ -39,7 +39,7 @@ internal class RetainedFramebuffer : IDisposable
{
if (_blob == null)
throw new ObjectDisposedException(nameof(RetainedFramebuffer));
return new LockedFramebuffer(_blob.Address, Size, RowBytes, dpi, Format, () =>
return new LockedFramebuffer(_blob.Address, Size, RowBytes, dpi, Format, AlphaFormat, () =>
{
blit(this);
GC.KeepAlive(this);
@@ -76,6 +76,7 @@ namespace Avalonia.Controls.Remote.Server
Stride,
new Vector(_dpi, _dpi),
new PlatformPixelFormat((PixelFormatEnum)Format),
Format == ProtocolPixelFormat.Rgb565 ? AlphaFormat.Opaque : AlphaFormat.Premul,
() =>
{
handle.Free();
@@ -29,6 +29,7 @@ namespace Avalonia.Native
public int RowBytes { get; set; }
public Vector Dpi { get; set; }
public PixelFormat Format { get; set; }
public AlphaFormat AlphaFormat { get; set; }
public void Dispose()
{
+1 -1
View File
@@ -133,7 +133,7 @@ namespace Avalonia.X11
return new LockedFramebuffer(
_blob.Address + Marshal.SizeOf<XcursorImage>(),
_pixelSize, _pixelSize.Width * 4,
new Vector(96, 96), PixelFormat.Bgra8888, null);
new Vector(96, 96), PixelFormat.Bgra8888, AlphaFormat.Premul, null);
}
public IFramebufferRenderTarget CreateFramebufferRenderTarget() => new FuncFramebufferRenderTarget(Lock);
+1 -1
View File
@@ -61,7 +61,7 @@ namespace Avalonia.X11
{
_fb?.Dispose();
_fb = null;
_fb = new RetainedFramebuffer(new PixelSize(width, height), PixelFormat.Bgra8888);
_fb = new RetainedFramebuffer(new PixelSize(width, height), PixelFormat.Bgra8888, AlphaFormat.Premul);
}
properties = new FramebufferLockProperties(framebufferValid);
+1 -1
View File
@@ -83,7 +83,7 @@ namespace Avalonia.X11
{
var h = GCHandle.Alloc(_bdata, GCHandleType.Pinned);
return new LockedFramebuffer(h.AddrOfPinnedObject(), new PixelSize(_width, _height), _width * 4,
new Vector(96, 96), PixelFormat.Bgra8888,
new Vector(96, 96), PixelFormat.Bgra8888, AlphaFormat.Premul,
() => h.Free());
}
@@ -47,7 +47,7 @@ partial class BrowserSoftwareRenderTarget : BrowserRenderTarget, IFramebufferPla
{
_fb?.Dispose();
_fb = null;
_fb = new RetainedFramebuffer(size, PixelFormat.Rgba8888);
_fb = new RetainedFramebuffer(size, PixelFormat.Rgba8888, AlphaFormat.Premul);
}
return _fb.Lock(new Vector(scaling * 96, scaling * 96), _parent._blit);
@@ -414,8 +414,8 @@ namespace Avalonia.Headless
public Vector Dpi { get; }
public PixelSize PixelSize { get; }
public PixelFormat? Format { get; }
public AlphaFormat? AlphaFormat { get; }
public PixelFormat? Format => PixelFormat.Rgba8888;
public AlphaFormat? AlphaFormat => Platform.AlphaFormat.Premul;
public int Version { get; set; }
public void Save(string fileName, int? quality = null)
@@ -434,7 +434,7 @@ namespace Avalonia.Headless
Version++;
var mem = Marshal.AllocHGlobal(PixelSize.Width * PixelSize.Height * 4);
return new LockedFramebuffer(mem, PixelSize, PixelSize.Width * 4, Dpi, PixelFormat.Rgba8888,
() => Marshal.FreeHGlobal(mem));
Platform.AlphaFormat.Premul, () => Marshal.FreeHGlobal(mem));
}
}
@@ -200,6 +200,7 @@ namespace Avalonia.Headless
public int RowBytes => _fb.RowBytes;
public Vector Dpi => _fb.Dpi;
public PixelFormat Format => _fb.Format;
public AlphaFormat AlphaFormat => _fb.AlphaFormat;
}
public ILockedFramebuffer Lock()
@@ -101,12 +101,17 @@ namespace Avalonia.LinuxFramebuffer.Output
public static LockedFramebuffer LockFb(IntPtr address, fb_var_screeninfo varInfo,
fb_fix_screeninfo fixedInfo, Vector dpi, Action? dispose)
{
var (format, alphaFormat) = varInfo switch
{
{ bits_per_pixel: 16 } => (PixelFormat.Rgb565, AlphaFormat.Opaque),
{ bits_per_pixel: 32, blue.offset: 16 } => (PixelFormat.Rgba8888, AlphaFormat.Premul),
_ => (PixelFormat.Bgra8888, AlphaFormat.Premul)
};
return new LockedFramebuffer(address,
new PixelSize((int)varInfo.xres, (int)varInfo.yres),
(int)fixedInfo.line_length, dpi,
varInfo.bits_per_pixel == 16 ? PixelFormat.Rgb565
: varInfo.blue.offset == 16 ? PixelFormat.Rgba8888
: PixelFormat.Bgra8888, dispose);
format, alphaFormat, dispose);
}
private void BlitToDevice()
@@ -67,7 +67,7 @@ namespace Avalonia.Skia
var framebuffer = _renderTargetWithProperties?.Lock(out lockProperties) ?? _renderTarget.Lock();
var framebufferImageInfo = new SKImageInfo(framebuffer.Size.Width, framebuffer.Size.Height,
framebuffer.Format.ToSkColorType(),
framebuffer.Format == PixelFormat.Rgb565 ? SKAlphaType.Opaque : SKAlphaType.Premul);
framebuffer.AlphaFormat.ToSkAlphaType());
CreateSurface(framebufferImageInfo, framebuffer);
_hadConversionShim |= _conversionShim != null;
+4 -2
View File
@@ -10,7 +10,7 @@ namespace Avalonia.Skia
/// <summary>
/// Immutable Skia bitmap.
/// </summary>
internal class ImmutableBitmap : IDrawableBitmapImpl, IReadableBitmapWithAlphaImpl
internal class ImmutableBitmap : IDrawableBitmapImpl, IReadableBitmapImpl
{
private readonly SKImage _image;
private readonly SKBitmap? _bitmap;
@@ -195,7 +195,9 @@ namespace Avalonia.Skia
if (_bitmap.ColorType.ToAvalonia() is not { } format)
throw new NotSupportedException($"Unsupported format {_bitmap.ColorType}");
return new LockedFramebuffer(_bitmap.GetPixels(), PixelSize, _bitmap.RowBytes, Dpi, format, null);
var alphaFormat = _bitmap.AlphaType.ToAlphaFormat();
return new LockedFramebuffer(_bitmap.GetPixels(), PixelSize, _bitmap.RowBytes, Dpi, format, alphaFormat, null);
}
}
}
@@ -238,6 +238,8 @@ namespace Avalonia.Skia
public Vector Dpi => _parent.Dpi;
/// <inheritdoc />
public PixelFormat Format => _bitmap.ColorType.ToPixelFormat();
public AlphaFormat AlphaFormat => _bitmap.AlphaType.ToAlphaFormat();
}
}
}
@@ -49,7 +49,7 @@ namespace Avalonia.Win32
return fb = new LockedFramebuffer(
framebufferData.Data.Address, framebufferData.Size, framebufferData.RowBytes,
GetCurrentDpi(), s_format, _onDisposeAction);
GetCurrentDpi(), s_format, AlphaFormat.Premul, _onDisposeAction);
}
finally
{
@@ -96,14 +96,14 @@ internal class Win32Icon : IDisposable
static IntPtr CreateHBitmap(Bitmap source)
{
using var fb = AllocFramebuffer(source.PixelSize, PixelFormats.Bgra8888);
source.CopyPixels(fb, AlphaFormat.Unpremul);
using var fb = AllocFramebuffer(source.PixelSize, PixelFormats.Bgra8888, AlphaFormat.Unpremul);
source.CopyPixels(fb);
return UnmanagedMethods.CreateBitmap(source.PixelSize.Width, source.PixelSize.Height, 1, 32, fb.Address);
}
static unsafe IntPtr AlphaToMask(Bitmap source)
{
using var alphaMaskBuffer = AllocFramebuffer(source.PixelSize, PixelFormats.BlackWhite);
using var alphaMaskBuffer = AllocFramebuffer(source.PixelSize, PixelFormats.BlackWhite, AlphaFormat.Opaque);
var height = alphaMaskBuffer.Size.Height;
var width = alphaMaskBuffer.Size.Width;
@@ -114,8 +114,8 @@ internal class Win32Icon : IDisposable
}
else
{
using var argbBuffer = AllocFramebuffer(source.PixelSize, PixelFormat.Bgra8888);
source.CopyPixels(argbBuffer, AlphaFormat.Unpremul);
using var argbBuffer = AllocFramebuffer(source.PixelSize, PixelFormat.Bgra8888, AlphaFormat.Unpremul);
source.CopyPixels(argbBuffer);
var pSource = (byte*)argbBuffer.Address;
var pDest = (byte*)alphaMaskBuffer.Address;
@@ -140,7 +140,7 @@ internal class Win32Icon : IDisposable
return UnmanagedMethods.CreateBitmap(width, height, 1, 1, alphaMaskBuffer.Address);
}
static LockedFramebuffer AllocFramebuffer(PixelSize size, PixelFormat format)
static LockedFramebuffer AllocFramebuffer(PixelSize size, PixelFormat format, AlphaFormat alphaFormat)
{
if (size.Width < 1 || size.Height < 1)
throw new ArgumentOutOfRangeException();
@@ -149,7 +149,7 @@ internal class Win32Icon : IDisposable
var data = Marshal.AllocHGlobal(size.Height * stride);
if (data == IntPtr.Zero)
throw new OutOfMemoryException();
return new LockedFramebuffer(data, size, stride, new Vector(96, 96), format,
return new LockedFramebuffer(data, size, stride, new Vector(96, 96), format, alphaFormat,
() => Marshal.FreeHGlobal(data));
}
@@ -83,7 +83,7 @@ public class DirectFbCompositionTests : TestBase
SKBitmap fb = new SKBitmap(200, 200, SKColorType.Rgba8888, SKAlphaType.Premul);
ILockedFramebuffer LockFb() => new LockedFramebuffer(fb.GetAddress(0, 0), new(fb.Width, fb.Height),
fb.RowBytes, new Vector(96, 96), PixelFormat.Rgba8888, null);
fb.RowBytes, new Vector(96, 96), PixelFormat.Rgba8888, AlphaFormat.Premul, null);
bool previousFrameIsRetained = false;
IFramebufferRenderTarget rt = advertised
@@ -25,10 +25,11 @@ namespace Avalonia.Skia.RenderTests
class Framebuffer : ILockedFramebuffer, IFramebufferPlatformSurface
{
public Framebuffer(PixelFormat fmt, PixelSize size)
public Framebuffer(PixelFormat fmt, AlphaFormat alphaFormat, PixelSize size)
{
Format = fmt;
var bpp = fmt == PixelFormat.Rgb565 ? 2 : 4;
AlphaFormat = alphaFormat;
Size = size;
RowBytes = bpp * size.Width;
Address = Marshal.AllocHGlobal(size.Height * RowBytes);
@@ -40,6 +41,8 @@ namespace Avalonia.Skia.RenderTests
public PixelFormat Format { get; }
public AlphaFormat AlphaFormat { get; }
public PixelSize Size { get; }
public int RowBytes { get; }
@@ -64,7 +67,7 @@ namespace Avalonia.Skia.RenderTests
{
var fmt = new PixelFormat(fmte);
var testName = nameof(FramebufferRenderResultsShouldBeUsableAsBitmap) + "_" + fmt;
var fb = new Framebuffer(fmt, new PixelSize(80, 80));
var fb = new Framebuffer(fmt, AlphaFormat.Premul, new PixelSize(80, 80));
var r = AvaloniaLocator.Current.GetRequiredService<IPlatformRenderInterface>();
using(var cpuContext = r.CreateBackendContext(null))
using (var target = cpuContext.CreateRenderTarget(new object[] { fb }))
@@ -174,7 +174,7 @@ public class CompositorTestServices : IDisposable
{
var ptr = Marshal.AllocHGlobal(128);
return new LockedFramebuffer(ptr, new PixelSize(1, 1), 4, new Vector(96, 96),
PixelFormat.Rgba8888, () => Marshal.FreeHGlobal(ptr));
PixelFormat.Rgba8888, AlphaFormat.Premul, () => Marshal.FreeHGlobal(ptr));
}
public IFramebufferRenderTarget CreateFramebufferRenderTarget() => new FuncFramebufferRenderTarget(Lock);