11 changed files with 303 additions and 22 deletions
@ -0,0 +1,32 @@ |
|||
using System; |
|||
using Avalonia.Metal; |
|||
using Avalonia.Utilities; |
|||
using Metal; |
|||
|
|||
namespace Avalonia.iOS; |
|||
|
|||
internal class MetalDevice : IMetalDevice |
|||
{ |
|||
private readonly DisposableLock _syncRoot = new(); |
|||
|
|||
public MetalDevice(IMTLDevice device) |
|||
{ |
|||
Device = device; |
|||
Queue = device.CreateCommandQueue(); |
|||
} |
|||
|
|||
public IMTLDevice Device { get; } |
|||
public IMTLCommandQueue Queue { get; } |
|||
IntPtr IMetalDevice.Device => Device.Handle; |
|||
IntPtr IMetalDevice.CommandQueue => Queue.Handle; |
|||
|
|||
public bool IsLost => false; |
|||
|
|||
public IDisposable EnsureCurrent() => _syncRoot.Lock(); |
|||
public object TryGetFeature(Type featureType) => null; |
|||
|
|||
public void Dispose() |
|||
{ |
|||
Queue.Dispose(); |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
using System; |
|||
using Avalonia.Metal; |
|||
using CoreAnimation; |
|||
|
|||
namespace Avalonia.iOS; |
|||
|
|||
internal class MetalDrawingSession : IMetalPlatformSurfaceRenderingSession |
|||
{ |
|||
private readonly MetalDevice _device; |
|||
private readonly ICAMetalDrawable _drawable; |
|||
|
|||
public MetalDrawingSession(MetalDevice device, ICAMetalDrawable drawable, PixelSize size, double scaling) |
|||
{ |
|||
_device = device; |
|||
_drawable = drawable; |
|||
Size = size; |
|||
Scaling = scaling; |
|||
Texture = _drawable.Texture.Handle; |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
var buffer = _device.Queue.CommandBuffer(); |
|||
buffer.PresentDrawable(_drawable); |
|||
buffer.Commit(); |
|||
} |
|||
|
|||
public IntPtr Texture { get; } |
|||
public PixelSize Size { get; } |
|||
|
|||
public double Scaling { get; } |
|||
|
|||
public bool IsYFlipped => false; |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
using System; |
|||
using Avalonia.Platform; |
|||
using Metal; |
|||
using SkiaSharp; |
|||
|
|||
namespace Avalonia.iOS; |
|||
#nullable enable |
|||
|
|||
internal class MetalPlatformGraphics : IPlatformGraphics |
|||
{ |
|||
private MetalPlatformGraphics() |
|||
{ |
|||
|
|||
} |
|||
|
|||
public bool UsesSharedContext => false; |
|||
public IPlatformGraphicsContext CreateContext() => new MetalDevice(MTLDevice.SystemDefault); |
|||
|
|||
public IPlatformGraphicsContext GetSharedContext() => throw new NotSupportedException(); |
|||
|
|||
public static MetalPlatformGraphics? TryCreate() |
|||
{ |
|||
var device = MTLDevice.SystemDefault; |
|||
if (device is null) |
|||
{ |
|||
// Can be null on unsupported OS versions.
|
|||
return null; |
|||
} |
|||
|
|||
#if !TVOS
|
|||
using var queue = device.CreateCommandQueue(); |
|||
using var context = GRContext.CreateMetal(new GRMtlBackendContext { Device = device, Queue = queue }); |
|||
if (context is null) |
|||
{ |
|||
// Can be null on macCatalyst because of older Skia bug.
|
|||
// Fixed in SkiaSharp 3.0
|
|||
return null; |
|||
} |
|||
#endif
|
|||
|
|||
return new MetalPlatformGraphics(); |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
using Avalonia.Metal; |
|||
using CoreAnimation; |
|||
|
|||
namespace Avalonia.iOS; |
|||
|
|||
internal class MetalPlatformSurface : IMetalPlatformSurface |
|||
{ |
|||
private readonly CAMetalLayer _layer; |
|||
private readonly AvaloniaView _avaloniaView; |
|||
|
|||
public MetalPlatformSurface(CAMetalLayer layer, AvaloniaView avaloniaView) |
|||
{ |
|||
_layer = layer; |
|||
_avaloniaView = avaloniaView; |
|||
} |
|||
public IMetalPlatformSurfaceRenderTarget CreateMetalRenderTarget(IMetalDevice device) |
|||
{ |
|||
var dev = (MetalDevice)device; |
|||
_layer.Device = dev.Device; |
|||
|
|||
var target = new MetalRenderTarget(_layer, dev); |
|||
_avaloniaView.SetRenderTarget(target); |
|||
return target; |
|||
} |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
using Avalonia.Metal; |
|||
using Avalonia.Platform; |
|||
using CoreAnimation; |
|||
using CoreGraphics; |
|||
using Foundation; |
|||
|
|||
namespace Avalonia.iOS; |
|||
|
|||
internal class MetalRenderTarget : IMetalPlatformSurfaceRenderTarget |
|||
{ |
|||
private readonly CAMetalLayer _layer; |
|||
private readonly MetalDevice _device; |
|||
private double _scaling = 1; |
|||
private PixelSize _size = new(1, 1); |
|||
|
|||
public MetalRenderTarget(CAMetalLayer layer, MetalDevice device) |
|||
{ |
|||
_layer = layer; |
|||
_device = device; |
|||
} |
|||
|
|||
public double PendingScaling { get; set; } = 1; |
|||
public PixelSize PendingSize { get; set; } = new(1, 1); |
|||
public void Dispose() |
|||
{ |
|||
} |
|||
|
|||
public IMetalPlatformSurfaceRenderingSession BeginRendering() |
|||
{ |
|||
// Flush all existing rendering
|
|||
var buffer = _device.Queue.CommandBuffer(); |
|||
buffer.Commit(); |
|||
buffer.WaitUntilCompleted(); |
|||
_size = PendingSize; |
|||
_scaling= PendingScaling; |
|||
_layer.DrawableSize = new CGSize(_size.Width, _size.Height); |
|||
|
|||
var drawable = _layer.NextDrawable() ?? throw new PlatformGraphicsContextLostException(); |
|||
return new MetalDrawingSession(_device, drawable, _size, _scaling); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue