Skip to content

Commit

Permalink
perf(Studio): Use custom-platform-control for SkiaSharp on macOS
Browse files Browse the repository at this point in the history
  • Loading branch information
psyGamer committed Nov 5, 2024
1 parent ad9f6e2 commit fcb21b8
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 1 deletion.
11 changes: 11 additions & 0 deletions Studio/CelesteStudio.GTK/SkiaDrawableHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ protected override bool OnDrawn(Context cr) {

return false;
}

protected override void Dispose(bool disposing) {
bitmap?.Dispose();
bitmap = null;

surface?.Dispose();
surface = null;

imageSurface?.Dispose();
imageSurface = null;
}
}

public bool CanFocus {
Expand Down
2 changes: 2 additions & 0 deletions Studio/CelesteStudio.Mac/CelesteStudio.Mac.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<RuntimeIdentifiers>osx-x64;osx-arm64</RuntimeIdentifiers>

<SupportedOSPlatformVersion>10.15</SupportedOSPlatformVersion>
Expand Down
6 changes: 5 additions & 1 deletion Studio/CelesteStudio.Mac/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using CelesteStudio.Communication;
using CelesteStudio.Controls;
using Eto.Forms;

namespace CelesteStudio.Mac;
Expand All @@ -8,7 +9,10 @@ public static class Program {
[STAThread]
public static void Main(string[] args) {
try {
new Application(Eto.Platforms.Mac64).Run(new Studio(args, _ => {}));
var platform = new Eto.Mac.Platform();
platform.Add<SkiaDrawable.IHandler>(() => new SkiaDrawableHandler());

new Application(platform).Run(new Studio(args, _ => {}));
} catch (Exception ex) {
Console.Error.WriteLine(ex);
ErrorLog.Write(ex);
Expand Down
92 changes: 92 additions & 0 deletions Studio/CelesteStudio.Mac/SkiaDrawableHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using CelesteStudio.Controls;
using Eto.Mac.Forms;
using MonoMac.AppKit;
using MonoMac.CoreGraphics;
using SkiaSharp;
using System;
using System.Runtime.InteropServices;

namespace CelesteStudio.Mac;

public class SkiaDrawableHandler : MacPanel<SkiaDrawableHandler.SkiaDrawableView, SkiaDrawable, SkiaDrawable.ICallback>, SkiaDrawable.IHandler {
public void Create() {
Enabled = true;
Control = new SkiaDrawableView(Widget);
}

public override NSView ContainerControl => Control;
public bool CanFocus {
get => true;
set { }
}

public class SkiaDrawableView(SkiaDrawable drawable) : MacPanelView {
private IntPtr bitmapData;
private int lastLength;

private SKSurface? surface;

private readonly CGColorSpace colorSpace = CGColorSpace.CreateDeviceRGB();
private CGDataProvider? dataProvider;
private CGImage? image;

public override void DrawRect(CGRect dirtyRect)
{
base.DrawRect(dirtyRect);

var bounds = new CGRect(drawable.DrawX, drawable.DrawY, drawable.DrawWidth, drawable.DrawHeight);
var info = new SKImageInfo((int)bounds.Width, (int)bounds.Height, SKColorType.Rgba8888, SKAlphaType.Premul);

// Allocate a memory block for the drawing process
int newLength = info.BytesSize;
if (lastLength != newLength)
{
lastLength = newLength;
if (bitmapData != IntPtr.Zero) {
bitmapData = Marshal.ReAllocCoTaskMem(bitmapData, newLength);
} else {
bitmapData = Marshal.AllocCoTaskMem(newLength);
}

surface?.Dispose();
surface = SKSurface.Create(info, bitmapData, info.RowBytes);

dataProvider?.Dispose();
dataProvider = new CGDataProvider(bitmapData, lastLength);

image?.Dispose();
image = new CGImage(
info.Width, info.Height,
8, info.BitsPerPixel, info.RowBytes,
colorSpace, CGBitmapFlags.ByteOrder32Big | CGBitmapFlags.PremultipliedLast,
dataProvider, null, false, CGColorRenderingIntent.Default);
}

using (new SKAutoCanvasRestore(surface!.Canvas, true)) {
drawable.Draw(surface);
}
surface.Canvas.Flush();

var ctx = NSGraphicsContext.CurrentContext.GraphicsPort;
ctx.DrawImage(bounds, image);
}

protected override void Dispose(bool disposing) {
Marshal.FreeCoTaskMem(bitmapData);

bitmapData = IntPtr.Zero;
lastLength = 0;

surface?.Dispose();
surface = null;

colorSpace.Dispose();

dataProvider?.Dispose();
dataProvider = null;

image?.Dispose();
image = null;
}
}
}

0 comments on commit fcb21b8

Please sign in to comment.