MetalPetal
基于Metal的图像处理框架。
设计概述
MetalPetal是基于Metal设计的图像处理框架,旨在提供易于使用的编程接口,以实现静态图像和视频的实时处理。
本章涵盖了MetalPetal的关键概念,并有助于您更好地理解其设计、实现、性能影响和最佳实践。
目标
MetalPetal 设计时考虑了以下目标:
-
易用的 API
提供便利的 API 并避免常见错误。
-
性能
高效地使用 CPU、GPU 和内存。
-
可扩展性
易于创建自定义过滤器,以及插件你的自定义图像处理单元。
-
Swift 优化
为 Swift 程序员提供流畅的使用体验。
核心组件
MetalPetal 的某些核心概念与苹果公司的 Core Image 框架中的概念非常相似。
MTIContext
为渲染 MTIImage
提供评估上下文。它也存储了大量的缓存以及状态信息,因此尽可能在可能的情况下重用上下文会更高效。
MTIImage
MTIImage
对象是待处理或生成的图像的表示。它不直接表示图像位图数据,而是包含生成图像(或更确切地说,MTLTexture
)所需的所有信息。它由两部分组成,生成纹理的配方(MTIImagePromise
)以及其他信息,例如 كيفية تطبيق المخزنة مما يساعد في تحسين أداء التطبيق (cachePolicy),以及如何手动生成从方式检查描述约束如何对纹理采样(samplerDescriptor)。
MTIFilter
MTIFilter
代表图像处理效果及控制该效果的任何参数。它生成一个输出MTIImage
对象。要使用滤波器,你需要创建滤波器对象,设置其输入图像和参数,然后访问其输出图像。通常,滤波器类拥有一个静态内核(MTIKernel
),当你访问其outputImage
属性时,它将与输入图像和参数一起请求内核以生成输出MTIImage
。
MTIKernel
MTIKernel
代表图像处理例程。MTIKernel
负责为滤波器创建相应的渲染或计算管线状态,以及为MTIImage
构建MTIImagePromise
。
优化
MetalPetal在底层为您进行了大量的优化。
它会自动缓存函数、内核状态、采样器状态等。
它利用Metal的特性,如可编程混合、无内存渲染目标、资源堆和Metal性能着色器,使渲染更快、更高效。在macOS上,MetalPetal还可以利用Apple硅的TBDR架构。
在渲染之前,MetalPetal可以查看您的图像渲染图,并计算出完成渲染所需的中间纹理的最小数量,从而节省内存、能量和时间。
如果可以连接多个“食谱”,则还可以重新组织图像渲染图,以消除冗余渲染阶段。(MTIContext.isRenderGraphOptimizationEnabled
)
并发考虑
MTIImage
对象是不可变的,这意味着它们可以在线程之间安全共享。
然而,MTIFilter
对象是可变的,因此不能在线程之间安全共享。
MTIContext
包含许多状态和缓存。有一个线程安全的机制用于MTIContext
对象,使得在多个线程之间共享MTIContext
对象是安全的。
比Core Image的优势
-
完全可定制的顶点和片段函数。
-
支持MRT(多个渲染目标)。
-
通常性能更优。(需要详细的基准数据)
内建过滤器
-
颜色矩阵
-
颜色查找
使用颜色查找表重新映射图像中的颜色。
-
不透明度
-
曝光度
-
饱和度
-
亮度
-
对比度
-
颜色反转
-
亮度
调整图像的饱和度,同时保持肤色适中。
-
RGB色调曲线
-
混合模式
- 正常
- 相乘
- 叠加
- 屏幕
- 硬光
- 柔光
- 变暗
- 变亮
- 色彩减淡
- 添加(线性减淡)
- 色彩加深
- 线性加深
- 浅色
- 深色
- 亮色
- 线性光
- 点光
- 硬混合
- 差值
- 排除
- 减去
- 除法
- 色调
- 饱和度
- 颜色
- 亮度
- 颜色查找512x512
- 自定义混合模式
-
与蒙版混合
-
变换
-
裁剪
-
像素化
-
多层合成
-
MPS 卷积
-
MPS 高斯模糊
-
MPS 定义
-
MPS 索贝尔
-
MPS 未 sharpened 面具
-
MPS盒式模糊
-
膨胀畸变
-
颜色键混合
-
色彩半色调
-
网点
-
圆角(圆形/连续曲线)
示例代码
MTIImage
创建一个 您可以从几乎所有图像数据源创建一个 MTIImage
对象,包括
- 引用要加载的图像文件的
URL
- 金属纹理
- CoreVideo 图像或像素缓冲区(
CVImageBufferRef
或CVPixelBufferRef
) - 内存中的图像位图数据
- 来自给定纹理或图像资源的纹理数据
- Core Image
CIImage
对象 MDLTexture
对象- SceneKit 和 SpriteKit 场景
let imageFromCGImage = MTIImage(cgImage: cgImage, isOpaque: true)
let imageFromCIImage = MTIImage(ciImage: ciImage)
let imageFromCoreVideoPixelBuffer = MTIImage(cvPixelBuffer: pixelBuffer, alphaType: .alphaIsOne)
let imageFromContentsOfURL = MTIImage(contentsOf: url)
// unpremultiply alpha if needed
let unpremultipliedAlphaImage = image.unpremultiplyingAlpha()
应用过滤器
let inputImage = ...
let filter = MTISaturationFilter()
filter.saturation = 0
filter.inputImage = inputImage
let outputImage = filter.outputImage
MTIImage
渲染 let options = MTIContextOptions()
guard let device = MTLCreateSystemDefaultDevice(), let context = try? MTIContext(device: device, options: options) else {
return
}
let image: MTIImage = ...
do {
try context.render(image, to: pixelBuffer)
//context.makeCIImage(from: image)
//context.makeCGImage(from: image)
} catch {
print(error)
}
MTIImage
显示 let imageView = MTIImageView(frame: self.view.bounds)
// You can optionally assign a `MTIContext` to the image view. If no context is assigned and `automaticallyCreatesContext` is set to `true` (the default value), a `MTIContext` is created automatically when the image view renders its content.
imageView.context = ...
imageView.image = image
如果您想将GPU命令编码过程从主线程移出,可以使用MTIThreadSafeImageView
。您可以在任何线程中将MTIImage
分配给MTIThreadSafeImageView
。
连接过滤器(Swift)
MetalPetal提供了用于连接过滤器的类型安全的Swift API。您可以在FilterGraph.makeImage
函数中使用=>
运算符连接过滤器并获取输出图像。
以下是一些示例:
let image = try? FilterGraph.makeImage { output in
inputImage => saturationFilter => exposureFilter => output
}
let image = try? FilterGraph.makeImage { output in
inputImage => saturationFilter => exposureFilter => contrastFilter => blendFilter.inputPorts.inputImage
exposureFilter => blendFilter.inputPorts.inputBackgroundImage
blendFilter => output
}
-
您可以直接使用
=>
连接一元过滤器(MTIUnaryFilter
)。 -
对于具有多个输入的过滤器,您需要连接到它的一个
inputPorts
。 -
=>
运算符仅在FilterGraph.makeImage
方法中使用。 -
只能将一个过滤器的输出连接到
output
。
处理视频文件
处理AVPlayer
let context = try MTIContext(device: device)
let asset = AVAsset(url: videoURL)
let composition = MTIVideoComposition(asset: asset, context: context, queue: DispatchQueue.main, filter: { request in
return FilterGraph.makeImage { output in
request.anySourceImage! => filterA => filterB => output
}!
}
let playerItem = AVPlayerItem(asset: asset)
playerItem.videoComposition = composition.makeAVVideoComposition()
player.replaceCurrentItem(with: playerItem)
player.play()
导出视频
VideoIO是需要使用以下示例的。
import VideoIO
var configuration = AssetExportSession.Configuration(fileType: .mp4, videoSettings: .h264(videoSize: composition.renderSize), audioSettings: .aac(channels: 2, sampleRate: 44100, bitRate: 128 * 1000))
configuration.videoComposition = composition.makeAVVideoComposition()
self.exporter = try! AssetExportSession(asset: asset, outputURL: outputURL, configuration: configuration)
exporter.export(progress: { progress in
}, completion: { error in
})
使用VideoIO处理实时视频
本示例需要VideoIO。
import VideoIO
// Setup Image View
let imageView = MTIImageView(frame: self.view.bounds)
...
// Setup Camera
let camera = Camera(captureSessionPreset: .hd1920x1080, configurator: .portraitFrontMirroredVideoOutput)
try camera.enableVideoDataOutput(on: DispatchQueue.main, delegate: self)
camera.videoDataOutput?.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_420YpCbCr8BiPlanarFullRange]
...
// AVCaptureVideoDataOutputSampleBufferDelegate
let filter = MTIColorInvertFilter()
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
return
}
let inputImage = MTIImage(cvPixelBuffer: pixelBuffer, alphaType: .alphaIsOne)
filter.inputImage = inputImage
self.imageView.image = filter.outputImage
}
有关预览和录制滤镜实时视频的更多信息,请参阅示例项目中的CameraFilterView.swift
。
最佳实践
-
尽可能重用
MTIContext
。上下文是重量级对象,因此如果需要创建它,应该尽早创建,并在每次需要渲染图像时重用。
-
明智地使用
MTIImage.cachePolicy
。当您不希望保留图像的渲染结果时,例如当图像是滤镜链中的中间结果时,使用
MTIImageCachePolicyTransient
,以便可以重用渲染结果的底层纹理。这是最内存高效的选择。然而,当您要求上下文渲染先前渲染的图像时,可能会重新渲染该图像,因为其底层纹理已被重用。默认情况下,滤镜的输出图像具有
transient
策略。当您想防止底层纹理被重用时,使用
MTIImageCachePolicyPersistent
。默认情况下,从外部源创建的图像具有
persistent
策略。 -
了解
MTIFilter.outputImage
是计算属性。每次您要求滤镜提供其输出图像时,滤镜可能会提供一个新的输出图像对象,即使输入与之前的调用相同。因此,尽可能重用输出图像。
例如,
// ╭→ filterB // filterA ─┤ // ╰→ filterC // // filterB and filterC use filterA's output as their input.
在这种情况下,以下
let filterOutputImage = filterA.outputImage filterB.inputImage = filterOutputImage filterC.inputImage = filterOutputImage
解决方案比
filterB.inputImage = filterA.outputImage filterC.inputImage = filterA.outputImage
构建自定义滤镜
如果您想在.metal
文件中包含MTIShaderLib.h,需要将MTIShaderLib.h
文件的路径添加到Metal编译器 - 头文件搜索路径
(MTL_HEADER_SEARCH_PATHS
)设置中。
例如,如果您使用CocoaPods,可以将MTL_HEADER_SEARCH_PATHS
设置为${PODS_CONFIGURATION_BUILD_DIR}/MetalPetal/MetalPetal.framework/Headers
或${PODS_ROOT}/MetalPetal/Frameworks/MetalPetal/Shaders
。如果您使用Swift Package Manager,设置MTL_HEADER_SEARCH_PATHS
为$(HEADER_SEARCH_PATHS)
着色器函数参数编码
MetalPetal 有一个内置机制来为您编码着色器函数参数。您可以将着色器函数参数作为 name: value
字典传递给 MTIRenderPipelineKernel.apply(toInputImages:parameters:outputDescriptors:)
、MTIRenderCommand(kernel:geometry:images:parameters:)
等。
例如,适用于 metal 函数 vibranceAdjust
的参数字典可以是
// Swift
let amount: Float = 1.0
let vibranceVector = float4(1, 1, 1, 1)
let parameters = ["amount": amount,
"vibranceVector": MTIVector(value: vibranceVector),
"avoidsSaturatingSkinTones": true,
"grayColorTransform": MTIVector(value: float3(0,0,0))]
// vibranceAdjust metal function
fragment float4 vibranceAdjust(...,
constant float & amount [[ buffer(0) ]],
constant float4 & vibranceVector [[ buffer(1) ]],
constant bool & avoidsSaturatingSkinTones [[ buffer(2) ]],
constant float3 & grayColorTransform [[ buffer(3) ]])
{
...
}
下表列出了着色器函数参数类型和参数字典中使用的对应类型。
着色器函数参数类型 | Swift | Objective-C |
---|---|---|
float | Float | float |
int | Int32 | int |
uint | UInt32 | uint |
bool | Bool | bool |
simd (float2,float4 float4x4, int4, 等.) | simd (使用 MetalPetal/Swift ) / MTIVector |
MTIVector |
struct | Data / MTIDataBuffer | NSData / MTIDataBuffer |
其他 (float * struct*, 等.) 不可变 | Data / MTIDataBuffer | NSData / MTIDataBuffer |
其他 (float * struct*, 等.) 可变 | MTIDataBuffer | MTIDataBuffer |
简单单输入/输出过滤器
要构建自定义一元过滤器,您可以继承 MTIUnaryImageRenderingFilter
并在 SubclassingHooks
类别中重写方法。示例:MTIPixellateFilter
、MTIVibranceFilter
、MTIUnpremultiplyAlphaFilter
、MTIPremultiplyAlphaFilter
等。
//Objective-C
@interface MTIPixellateFilter : MTIUnaryImageRenderingFilter
@property (nonatomic) float fractionalWidthOfAPixel;
@end
@implementation MTIPixellateFilter
- (instancetype)init {
if (self = [super init]) {
_fractionalWidthOfAPixel = 0.05;
}
return self;
}
+ (MTIFunctionDescriptor *)fragmentFunctionDescriptor {
return [[MTIFunctionDescriptor alloc] initWithName:@"pixellateEffect" libraryURL:[bundle URLForResource:@"default" withExtension:@"metallib"]];
}
- (NSDictionary<NSString *,id> *)parameters {
return @{@"fractionalWidthOfAPixel": @(self.fractionalWidthOfAPixel)};
}
@end
//Swift
class MTIPixellateFilter: MTIUnaryImageRenderingFilter {
var fractionalWidthOfAPixel: Float = 0.05
override var parameters: [String : Any] {
return ["fractionalWidthOfAPixel": fractionalWidthOfAPixel]
}
override class func fragmentFunctionDescriptor() -> MTIFunctionDescriptor {
return MTIFunctionDescriptor(name: "pixellateEffect", libraryURL: MTIDefaultLibraryURLForBundle(Bundle.main))
}
}
完全自定义过滤器
要构建更复杂的过滤器,您只需创建一个内核 (MTIRenderPipelineKernel
/MTIComputePipelineKernel
/MTIMPSKernel
),然后将内核应用于输入图像即可。示例:MTIChromaKeyBlendFilter
、MTIBlendWithMaskFilter
、MTIColorLookupFilter
等。
@interface MTIChromaKeyBlendFilter : NSObject <MTIFilter>
@property (nonatomic, strong, nullable) MTIImage *inputImage;
@property (nonatomic, strong, nullable) MTIImage *inputBackgroundImage;
@property (nonatomic) float thresholdSensitivity;
@property (nonatomic) float smoothing;
@property (nonatomic) MTIColor color;
@end
@implementation MTIChromaKeyBlendFilter
@synthesize outputPixelFormat = _outputPixelFormat;
+ (MTIRenderPipelineKernel *)kernel {
static MTIRenderPipelineKernel *kernel;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
kernel = [[MTIRenderPipelineKernel alloc] initWithVertexFunctionDescriptor:[[MTIFunctionDescriptor alloc] initWithName:MTIFilterPassthroughVertexFunctionName] fragmentFunctionDescriptor:[[MTIFunctionDescriptor alloc] initWithName:@"chromaKeyBlend"]];
});
return kernel;
}
- (instancetype)init {
if (self = [super init]) {
_thresholdSensitivity = 0.4;
_smoothing = 0.1;
_color = MTIColorMake(0.0, 1.0, 0.0, 1.0);
}
return self;
}
- (MTIImage *)outputImage {
if (!self.inputImage || !self.inputBackgroundImage) {
return nil;
}
return [self.class.kernel applyToInputImages:@[self.inputImage, self.inputBackgroundImage]
parameters:@{@"color": [MTIVector vectorWithFloat4:(simd_float4){self.color.red, self.color.green, self.color.blue,self.color.alpha}],
@"thresholdSensitivity": @(self.thresholdSensitivity),
@"smoothing": @(self.smoothing)}
outputTextureDimensions:MTITextureDimensionsMake2DFromCGSize(self.inputImage.size)
outputPixelFormat:self.outputPixelFormat];
}
@end
单次渲染通道中的多次绘制调用
您可以使用 MTIRenderCommand
在单次渲染通道中发出多次绘制调用。
// Create a draw call with kernelA, geometryA, and imageA.
let renderCommandA = MTIRenderCommand(kernel: self.kernelA, geometry: self.geometryA, images: [imageA], parameters: [:])
// Create a draw call with kernelB, geometryB, and imageB.
let renderCommandB = MTIRenderCommand(kernel: self.kernelB, geometry: self.geometryB, images: [imageB], parameters: [:])
// Create an output descriptor
let outputDescriptor = MTIRenderPassOutputDescriptor(dimensions: MTITextureDimensions(width: outputWidth, height: outputHeight, depth: 1), pixelFormat: .bgra8Unorm, loadAction: .clear, storeAction: .store)
// Get the output images, the output image count is equal to the output descriptor count.
let images = MTIRenderCommand.images(byPerforming: [renderCommandA, renderCommandB], outputDescriptors: [outputDescriptor])
您还可以创建多个输出描述符以在单次渲染通道中输出多个图像(MRT,请参见 https://en.wikipedia.org/wiki/Multiple_Render_Targets)。
自定义顶点数据
当 MTIVertex
无法满足您的需求时,您可以实现 MTIGeometry
协议,向命令编码器提供您的自定义顶点数据。
使用 MTIRenderCommand
API 发出绘制调用并传递您的自定义 MTIGeometry
。
自定义处理模块
在罕见情况下,您可能希望直接访问底层纹理,在一个渲染通道中使用多个 MPS 内核,执行 3D 渲染,或自行编码渲染命令。
MTIImagePromise
协议为 MetalPetal 中的一步提供对底层纹理和渲染上下文的直接访问。
通过实现 MTIImagePromise
协议,您可以创建新的输入源或完全自定义的处理单元。您可能需要导入一个额外的模块才能这样做。
Objective-C
@import MetalPetal.Extension;
Swift
// CocoaPods
import MetalPetal.Extension
// Swift Package Manager
import MetalPetalObjectiveC.Extension
例如,请参阅 MTIComputePipelineKernel
、MTICLAHELUTRecipe
或 MTIImage
的实现。
Alpha 类型
如果图像使用了 Alpha 通道,则有两种常见的表示方式:未预乘(直接/不相关)Alpha,和预乘(相关)Alpha。
在未预乘 Alpha 中,RGB 分量代表像素的颜色,不考虑其不透明度。
在预乘 Alpha 中,RGB 分量代表像素的颜色,并且通过乘法调整其不透明度。
MetalPetal 会显式处理 Alpha 类型。您负责在创建图像时提供正确的 Alpha 类型。
在 MetalPetal 中有三种子 Alpha 类型。
MTIAlphaType.nonPremultiplied
:图像中的 Alpha 值未预乘。
MTIAlphaType.premultiplied
:图像中的 Alpha 值已预乘。
MTIAlphaType.alphaIsOne
:图像中没有 Alpha 通道,或者图像是不透明的。
通常,CGImage
、CVPixelBuffer
和 CIImage
对象具有预乘 Alpha 通道。如果您的不透明图像,例如来自摄像头输入的 CVPixelBuffer
或从 jpg
文件加载的 CGImage
,请强烈推荐使用 MTIAlphaType.alphaIsOne
。
您可以在 MTIImage
上调用 unpremultiplyingAlpha()
或 premultiplyingAlpha()
来转换图像的 Alpha 类型。
出于性能原因,Alpha 类型验证仅在调试构建中发生。
内置滤镜的Alpha处理
-
MetalPetal中的大多数滤镜均接受未预乘Alpha和对透明图像的支持,并输出未预乘Alpha图像。
-
具有
outputAlphaType
属性的滤镜接受所有Alpha类型的输入。您可以使用outputAlphaType
来指定输出图像的Alpha类型。例如:
MTIBlendFilter
,MTIMultilayerCompositingFilter
,MTICoreImageUnaryFilter
,MTIRGBColorSpaceConversionFilter
-
不实际更改颜色的滤镜采用透明度透传处理规则,即输出图像的Alpha类型与输入图像相同。
例如:
MTITransformFilter
,MTICropFilter
,MTIPixellateFilter
,MTIBulgeDistortionFilter
有关Alpha类型和Alpha合成的更多信息,请参阅Bartosz Ciechanowski的这篇令人惊叹的互动文章:Alpha合成。
色彩空间
色彩空间在图像处理中至关重要。没有色彩空间,红、绿、蓝分量的数值就无意义。
在继续了解MetalPetal如何处理色彩空间之前,您可能需要了解色彩空间是什么以及它如何影响颜色值的表示。网上有许多关于色彩空间的解释文章,您可以从中入门,建议阅读色彩空间 - 由Bartosz Ciechanowski撰写。
不同的软件和框架处理色彩空间的方式不同。例如,Photoshop具有默认的sRGB IEC61966-2.1工作色彩空间,而Core Image默认使用线性sRGB工作色彩空间。
Metal纹理不存储任何色彩空间信息。MetalPetal中的多数色彩空间处理发生在图像数据输入(MTIImage(...)
)和输出(MTIContext.render...
)时。
输入的色彩空间
为输入指定色彩空间意味着MetalPetal应在创建纹理时将源色彩值转换为指定的色彩空间。
-
当从
URL
或CGImage
加载时,您可以使用MTICGImageLoadingOptions
指定纹理数据使用的颜色空间。如果您在加载图像时不指定任何选项,则使用设备 RGB 颜色空间(MTICGImageLoadingOptions.default
)。一个nil
颜色空间将禁用颜色匹配,这等价于使用输入图像的颜色空间来创建MTICGImageLoadingOptions
。如果指定颜色空间的模式不是 RGB,则使用设备 RGB 颜色空间作为后备。 -
当从
CIImage
加载时,您可以使用MTICIImageRenderingOptions
指定纹理数据使用的颜色空间。如果您在加载CIImage
时不指定任何选项,则使用设备 RGB 颜色空间(MTICIImageRenderingOptions.default
)。一个nil
颜色空间将禁用颜色匹配,颜色值将在CIContext
的工作颜色空间中加载。
输出颜色空间
指定输出颜色空间时,颜色空间更多像是一个标签,用于与系统通信如何表示输出中的颜色值。实际上并没有执行颜色空间转换。
-
您可以使用
MTIContext.makeCGImage...
或MTIContext.startTaskTo...
方法并通过colorSpace
参数指定输出CGImage
的颜色空间。 -
您可以使用
MTICIImageCreationOptions
指定输出CIImage
的颜色空间。
如果没有指定输出颜色空间,MetalPetal假定输出颜色值位于设备 RGB 颜色空间。
CVPixelBuffer
的颜色空间
由于 MetalPetal 使用 CVMetalTextureCache
和 IOSurface
直接将 CVPixelBuffer
映射到 Metal 纹理,因此您无法为从 CVPixelBuffer
加载或渲染指定颜色空间。但是,您可以选择是否使用具有 sRGB 像素格式的纹理进行映射。
在 Metal 中,如果像素格式名称具有 _sRGB
后缀,则在读取和写入像素中的颜色值时将应用 sRGB 灰度压缩和解压缩。这意味着具有 _sRGB
像素格式的纹理假定它存储的颜色值是 sRGB 灰度校正的,当在着色器中读取颜色值时,执行 sRGB 到线性 RGB 的转换。当在着色器中写入颜色值时,执行线性 RGB 到 sRGB 的转换。
颜色空间转换
您可以使用MTIRGBColorSpaceConversionFilter
来执行色彩空间转换。色彩空间转换函数也包含在MTIShaderLib.h
中。
metalpetal::sRGBToLinear
(sRGB IEC61966-2.1到线性sRGB)metalpetal::linearToSRGB
(线性sRGB到sRGB IEC61966-2.1)metalpetal::linearToITUR709
(线性sRGB到ITU-R 709)metalpetal::ITUR709ToLinear
(ITU-R 709到线性sRGB)
扩展
与SceneKit一起工作
您可以使用MTISCNSceneRenderer
将SCNScene
生成MTIImage
。您可能需要处理SceneKit渲染器的线性RGB色彩空间,参见问题#76 SceneKit生成的图片比正常颜色暗。
与SpriteKit一起工作
您可以使用MTISKSceneRenderer
从SKScene
生成MTIImage
。
与Core Image一起工作
您可以从CIImage
创建MTIImage
。
您可以使用MTIContext
将MTIImage
渲染为CIImage
。
您可以直接使用CIFilter
与MTICoreImageKernel
或MTICoreImageUnaryFilter
类一起使用。(仅限Swift)
与JavaScript一起工作
使用MetalPetalJS,您可以使用JavaScript创建渲染管线和过滤器,使其能够从“云”中下载您的过滤器/渲染器。
纹理加载器
建议您使用接受 MTICGImageLoadingOptions
的 API 来加载 CGImage
和从 URL
加载的图片,而不是使用接受 MTKTextureLoaderOption
的 API。
当您使用接受 MTKTextureLoaderOption
的 API 时,MetalPetal 默认使用 MTIDefaultTextureLoader
来加载 CGImage
、从 URL
加载的图片和命名图片。《MTIDefaultTextureLoader》 在内部使用 MTKTextureLoader
,并且在性能上有细微的成本为处理 MTKTextureLoader
的一致性和错误提供了一个解决方案。您还可以通过实现 MTITextureLoader
协议来自定义纹理加载程序。然后,在创建 MTIContext
时,将您的纹理加载程序类分配给 MTIContextOptions.textureLoaderClass
。
安装
CocoaPods
您可以使用 CocoaPods 来安装最新版本。
use_frameworks!
pod 'MetalPetal'
# Required if you are using Swift.
pod 'MetalPetal/Swift'
# Recommended if you'd like to run MetalPetal on Apple silicon Macs.
pod 'MetalPetal/AppleSilicon'
Swift
子库 提供针对 Objective-C API 的 Swift 特定的补充和修改,以改进它们映射到 Swift。如果您使用 Swift,则高度推荐使用。
AppleSilicon
子库 提供默认的 Metal Shading Language v2.3 编译库,用于在 Apple Silicon Mac 上启用可编程混合支持。
Swift 包管理器
iOS 模拟器支持
MetalPetal 可以在 Xcode 11+ 和 macOS 10.15+ 的模拟器上运行。
MetalPerformanceShaders.framework
在模拟器上不可用,因此依赖于 MetalPerformanceShaders
的过滤器(如 MTIMPSGaussianBlurFilter
、MTICLAHEFilter
)无法工作。
模拟器支持的特性少于实际 Apple GPU,或具有不同的实施限制。请参阅 在模拟器中运行 Metal 应用程序的开发 获取详细信息。
快速查看调试支持
如果您对 MTIImage
执行快速查看,它将显示您构成的图像图以生成该图像。
趣味事实
贡献
感谢您考虑为 MetalPetal 做贡献。请阅读我们的 贡献指南。
许可证
MetalPetal遵循MIT许可证。 LICENSE
位于/MetalPetalExamples
目录中的文件受其他许可证的约束。LICENSE.md
文档遵循CC-BY-4.0许可。