I am building a .NET MAUI app that's designed to run on iOS, specifically on an iPad Pro. In it I need to be be able to sample sections of an image based on a number of parameters and display that on screen, so I thought the best way to do that would be through a shader and the SkiaSharp SKRuntimeEffect and SKShader classes seemed like a good way to do it. I made a custom control that inherits from SKCanvasView and wrote an SkSL shader. However, whenever the code reaches the DrawRect() call in the OnPaintSurface method of the class, the app crashes immediately.
I have made a bare bones app that has only a custom control with a trivial shader that just sets each pixel colour to red and the crash still happens. The code for the custom control is:
using SkiaSharp;
using SkiaSharp.Views.Maui.Controls;
using System.Diagnostics;
namespace SkiaShaderTest.Controls
{
public class Panel : SKCanvasView
{
public static BindableProperty ShaderOnProperty = BindableProperty.Create(
nameof(ShaderOn),
typeof(bool),
typeof(Panel),
false,
propertyChanged: (bindable, oldValue, newValue) =>
{
var panel = (Panel)bindable;
panel.InvalidateSurface();
}
);
public bool ShaderOn
{
get => (bool)GetValue(ShaderOnProperty);
set => SetValue(ShaderOnProperty, value);
}
protected override void OnPaintSurface(SkiaSharp.Views.Maui.SKPaintSurfaceEventArgs args)
{
var canvas = args.Surface.Canvas;
var info = args.Info;
canvas.Clear();
if (ShaderOn)
{
var src = @"
float4 main(float2 fragCoord) {
return float4(1,0,0,1);
}";
using var effect = SKRuntimeEffect.Create(src, out string error);
using var shader = effect.ToShader(true);
using (SKPaint paint = new SKPaint() { Shader = shader })
{
try
{
canvas.DrawRect(info.Rect, paint);
}
catch (Exception e)
{
Debug.WriteLine($"Exception {e.GetType()}: {e.Message}");
}
}
}
else
{
using (SKPaint paint = new SKPaint())
{
paint.Color = SKColors.BlueViolet;
canvas.DrawRect(info.Rect, paint);
}
}
}
}
}
And this is the xaml layout of the app:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="SkiaShaderTest.MainPage"
xmlns:controls="clr-namespace:SkiaShaderTest.Controls"
>
<Grid RowDefinitions="*,auto" IgnoreSafeArea="True">
<controls:Panel x:Name="panel"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
Grid.Row="0"
Grid.RowSpan="2"/>
<CheckBox
IsChecked="{Binding ShaderOn, Source={x:Reference panel}, Mode=TwoWay}"
MinimumWidthRequest="100"
BackgroundColor="RoyalBlue"
Color="AliceBlue"
HorizontalOptions="Center"
VerticalOptions="End"
/>
</Grid>
</ContentPage>
The full code of this example app can be found here: https://github.com/LFLumirithmic/SkiaShaderTest
Every time the line canvas.DrawRect(info.Rect, paint);
is reached (when the ShaderOn flag is set to true), the app crashes instantly.
I have tried it on the iPad itself (it's an iPad Pro (12.9 inch) (4th generation)), in an iOS simulator, on the Mac Mini that I use to build to the iPad and on a separate Windows 11 laptop. On the iPad it crashes with no error messages or console output whatsoever, without even throwing an exception. On the Mac, it also doesn't throw an exception, but gives the following console output: https://github.com/LFLumirithmic/SkiaShaderTest/blob/main/mac-console-output.rtf
On Windows, however, it does throw an exception with this output:
System.Runtime.InteropServices.SEHException
HResult=0x80004005
Message=External component has thrown an exception.
Source=<Cannot evaluate the exception source>
StackTrace:
<Cannot evaluate the exception stack trace>
(note that it doesn't reach the code in the catch
block, the visual studio debugger simply throws the exception at the actual DrawRect() line)
I tried to create one of the default shaders that can be created using the SkiaSharp C# API, for example:
using (SKPaint paint = new SKPaint())
{
SKShader shader = SKShader.CreateLinearGradient(
new SKPoint(0, 0),
new SKPoint(1000, 1000),
new SKColor[]
{
new SKColor(0,0,255),
new SKColor(0,255,0)
},
null,
SKShaderTileMode.Repeat
);
paint.Shader = shader;
canvas.DrawRect(info.Rect, paint);
}
and that works perfectly.
These are the SkiaSharp packages I've got installed through NuGet in my Visual Studio project
As far as I can tell, these are the correct packages and the latest versions thereof.
The console output I see on the Mac and the exception thrown on Windows seem to point to there being an error inside SkiaSharp itself, but I very much don't want to discount the possibility that I'm doing something wrong.
Does anyone have an idea of what I might be doing wrong and/or how this issue might be fixed?