Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Metal as a backend on Mac Catalyst #2747

Merged
merged 1 commit into from
Feb 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading