Skip to content

Commit

Permalink
Use Metal as a backend on Mac Catalyst (#2747)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattleibow authored Feb 10, 2024
1 parent 0176323 commit 01a3218
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -1,19 +1,127 @@
using System;
using Microsoft.Maui.Handlers;
using SkiaSharp.Views.iOS;
using SkiaSharp.Views.Maui.Platform;
using UIKit;

namespace SkiaSharp.Views.Maui.Handlers
{
public partial class SKGLViewHandler : ViewHandler<ISKGLView, UIView>
public partial class SKGLViewHandler : ViewHandler<ISKGLView, SKMetalView>
{
protected override UIView CreatePlatformView() => throw new PlatformNotSupportedException("OpenGL-based views (such as SKGLView) are not supported on Mac Catalyst. Instead, use Metal-based views.");
private SKSizeI lastCanvasSize;
private GRContext? lastGRContext;
private SKTouchHandler? touchHandler;

public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view) { }
protected override SKMetalView CreatePlatformView() =>
new MauiSKMetalView
{
BackgroundColor = UIColor.Clear,
Opaque = false,
};

public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view) { }
protected override void ConnectHandler(SKMetalView platformView)
{
platformView.PaintSurface += OnPaintSurface;

public static void MapEnableTouchEvents(SKGLViewHandler handler, ISKGLView view) { }
base.ConnectHandler(platformView);
}

public static void OnInvalidateSurface(SKGLViewHandler handler, ISKGLView view, object? args) { }
protected override void DisconnectHandler(SKMetalView platformView)
{
touchHandler?.Detach(platformView);
touchHandler = null;

platformView.PaintSurface -= OnPaintSurface;

base.DisconnectHandler(platformView);
}

// Mapper actions / properties

public static void OnInvalidateSurface(SKGLViewHandler handler, ISKGLView view, object? args)
{
if (handler.PlatformView.Paused && handler.PlatformView.EnableSetNeedsDisplay)
handler.PlatformView.SetNeedsDisplay();
}

public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view)
{
if (handler.PlatformView is MauiSKMetalView pv)
{
pv.IgnorePixelScaling = view.IgnorePixelScaling;
handler.PlatformView.SetNeedsDisplay();
}
}

public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view)
{
handler.PlatformView.Paused = !view.HasRenderLoop;
handler.PlatformView.EnableSetNeedsDisplay = !view.HasRenderLoop;
}

public static void MapEnableTouchEvents(SKGLViewHandler handler, ISKGLView view)
{
handler.touchHandler ??= new SKTouchHandler(
args => view.OnTouch(args),
(x, y) => handler.OnGetScaledCoord(x, y));

handler.touchHandler?.SetEnabled(handler.PlatformView, view.EnableTouchEvents);
}

// helper methods

private void OnPaintSurface(object? sender, iOS.SKPaintMetalSurfaceEventArgs e)
{
var newCanvasSize = e.Info.Size;
if (lastCanvasSize != newCanvasSize)
{
lastCanvasSize = newCanvasSize;
VirtualView?.OnCanvasSizeChanged(newCanvasSize);
}
if (sender is SKMetalView platformView)
{
var newGRContext = platformView.GRContext;
if (lastGRContext != newGRContext)
{
lastGRContext = newGRContext;
VirtualView?.OnGRContextChanged(newGRContext);
}
}

VirtualView?.OnPaintSurface(new SKPaintGLSurfaceEventArgs(e.Surface, e.BackendRenderTarget, e.Origin, e.Info, e.RawInfo));
}

private SKPoint OnGetScaledCoord(double x, double y)
{
if (VirtualView?.IgnorePixelScaling == false && PlatformView != null)
{
var scale = PlatformView.ContentScaleFactor;

x *= scale;
y *= scale;
}

return new SKPoint((float)x, (float)y);
}

private class MauiSKMetalView : SKMetalView
{
public bool IgnorePixelScaling { get; set; }

protected override void OnPaintSurface(iOS.SKPaintMetalSurfaceEventArgs e)
{
if (IgnorePixelScaling)
{
var userVisibleSize = new SKSizeI((int)Bounds.Width, (int)Bounds.Height);
var canvas = e.Surface.Canvas;
canvas.Scale((float)ContentScaleFactor);
canvas.Save();

e = new iOS.SKPaintMetalSurfaceEventArgs(e.Surface, e.BackendRenderTarget, e.Origin, e.Info.WithSize(userVisibleSize), e.Info);
}

base.OnPaintSurface(e);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
<Compile Remove="**\*.iOS.cs" />
<None Include="**\*.iOS.cs" />
</ItemGroup>
<!-- macOS -->
<!-- Mac Catalyst -->
<ItemGroup Condition="!$(TargetFramework.Contains('-maccatalyst'))">
<Compile Remove="**\MacCatalyst\**\*.cs" />
<None Include="**\MacCatalyst\**\*.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if !__WASM__ && (!UNO_REFERENCE_API || (NET6_0_OR_GREATER && (__IOS__ || __MACOS__)))
#if !__WASM__ && (!UNO_REFERENCE_API || (NET6_0_OR_GREATER && (__IOS__ || __MACOS__))) && !MACCATALYST
// Note that `(!UNO_REFERENCE_API || (NET6_0_OR_GREATER && (__IOS__ || __MACOS__)))` is required
// because of https://github.com/unoplatform/uno/issues/8814, where !UNO_REFERENCE_API should be enough.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
#if !MACCATALYST || HAS_UNO_WINUI
using System;
using System.ComponentModel;

#if HAS_UNO_WINUI
Expand Down Expand Up @@ -68,3 +69,4 @@ public SKPaintGLSurfaceEventArgs(SKSurface surface, GRBackendRenderTarget render
public SKImageInfo RawInfo { get; private set; }
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,23 @@ public SKPaintMetalSurfaceEventArgs(SKSurface surface, GRBackendRenderTarget ren
BackendRenderTarget = renderTarget;
ColorType = colorType;
Origin = origin;
Info = new SKImageInfo(renderTarget.Width, renderTarget.Height, ColorType);
RawInfo = Info;
}

public SKPaintMetalSurfaceEventArgs(SKSurface surface, GRBackendRenderTarget renderTarget, GRSurfaceOrigin origin, SKImageInfo info)
: this(surface, renderTarget, origin, info, info)
{
}

public SKPaintMetalSurfaceEventArgs(SKSurface surface, GRBackendRenderTarget renderTarget, GRSurfaceOrigin origin, SKImageInfo info, SKImageInfo rawInfo)
{
Surface = surface;
BackendRenderTarget = renderTarget;
ColorType = info.ColorType;
Origin = origin;
Info = info;
RawInfo = rawInfo;
}

public SKSurface Surface { get; private set; }
Expand All @@ -29,6 +46,10 @@ public SKPaintMetalSurfaceEventArgs(SKSurface surface, GRBackendRenderTarget ren
public SKColorType ColorType { get; private set; }

public GRSurfaceOrigin Origin { get; private set; }

public SKImageInfo Info { get; private set; }

public SKImageInfo RawInfo { get; private set; }
}
}
#endif

0 comments on commit 01a3218

Please sign in to comment.