我正在构建一个 .NET MAUI 应用程序,该应用程序设计为在 iOS 上运行,特别是在 iPad Pro 上。在其中,我需要能够根据多个参数对图像的各个部分进行采样并将其显示在屏幕上,因此我认为最好的方法是通过着色器,而 SkiaSharp SKRuntimeEffect 和 SKShader 类似乎是好方法。我制作了一个继承自 SKCanvasView 的自定义控件并编写了一个 SkSL 着色器。但是,每当代码到达类的 OnPaintSurface 方法中的 DrawRect() 调用时,应用程序就会立即崩溃。
我制作了一个简单的应用程序,它只有一个自定义控件和一个简单的着色器,只需将每个像素颜色设置为红色,并且崩溃仍然发生。自定义控件的代码是:
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);
}
}
}
}
}
这是应用程序的 xaml 布局:
<?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>
此示例应用程序的完整代码可以在这里找到:https://github.com/LFLumirithmic/SkiaShaderTest
每次到达
canvas.DrawRect(info.Rect, paint);
行(当 ShaderOn 标志设置为 true 时),应用程序会立即崩溃。
我已经在 iPad 本身(iPad Pro(12.9 英寸)(第四代))、iOS 模拟器、我用来构建 iPad 的 Mac Mini 以及单独的 Windows 11 笔记本电脑上进行了尝试。在 iPad 上,它崩溃了,没有任何错误消息或控制台输出,甚至没有抛出异常。在 Mac 上,它也不会抛出异常,但会提供以下控制台输出:https://github.com/LFLumirithmic/SkiaShaderTest/blob/main/mac-console-output.rtf
但是,在 Windows 上,它确实会抛出以下输出的异常:
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>
(请注意,它没有到达
catch
块中的代码,Visual Studio 调试器只是在实际的 DrawRect() 行抛出异常)
我尝试创建可以使用 SkiaSharp C# API 创建的默认着色器之一,例如:
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);
}
效果非常好。
这些是我通过 NuGet 在 Visual Studio 项目中安装的 SkiaSharp 软件包
据我所知,这些是正确的软件包及其最新版本。
我在 Mac 上看到的控制台输出和 Windows 上抛出的异常似乎表明 SkiaSharp 本身内部存在错误,但我非常不想低估我做错了什么的可能性。
有人知道我可能做错了什么和/或如何解决这个问题吗?
我知道这已经很老了,你可能已经明白了这一点,但对于遇到这个问题的其他人来说:
我刚刚遇到了同样的问题,并设法通过添加来解决“insta-crash”问题
uniform float2 iResolution;
uniform float iTime;
在
vec4 main(vec2 fragCoord) {
线上方。
现在,我没有崩溃,只是黑屏。仍在研究为什么它有效,但至少应用程序不再崩溃。