Flutter 工程中,iOS 端接入 Metal,我使用的是 Texture
来展示对应 View。
具体调用方法是通过 MethodChannel 还是 ffi 这边不再赘述。
使用 Texture
来展示效果需要原生继承 FlutterTexture
协议并实现- (CVPixelBufferRef _Nullable)copyPixelBuffer;
方法。
以下是核心代码:
import Foundation
import CoreVideo
import Metal
import Flutter
class MetalTexture: NSObject {
var sourceImageBuf: CVMetalTexture?
var pixelBuf: Unmanaged<CVPixelBuffer>?
var textureCache: CVMetalTextureCache?
init(width: Int, height: Int) {
super.init()
guard let defaultDevice = MTLCreateSystemDefaultDevice() else {
fatalError("Could not create Metal Device")
}
guard let ioSurface = IOSurfaceCreate([
kIOSurfaceWidth: width,
kIOSurfaceHeight: height,
kIOSurfaceBytesPerElement: 4,
kIOSurfacePixelFormat: kCVPixelFormatType_32BGRA] as [CFString : Any] as CFDictionary) else {
fatalError("IOSurfaceCreate error.")
}
guard CVPixelBufferCreateWithIOSurface(
kCFAllocatorDefault,
ioSurface,
[kCVPixelBufferMetalCompatibilityKey: true] as CFDictionary,
&pixelBuf) == kCVReturnSuccess else {
fatalError("CVPixelBufferCreateWithIOSurface create CVPixelBuffer error")
}
guard CVMetalTextureCacheCreate(kCFAllocatorDefault,
nil,
defaultDevice,
nil,
&textureCache) == kCVReturnSuccess else {
fatalError("Failed to create texture cache")
}
guard let textureCache = textureCache else { return }
guard CVMetalTextureCacheCreateTextureFromImage(
kCFAllocatorDefault,
textureCache,
pixelBuf!.takeUnretainedValue(),
nil,
.bgra8Unorm,
width,
height,
0,
&sourceImageBuf) == kCVReturnSuccess else {
fatalError("CVMetalTextureCacheCreateTextureFromImage bind CVPixelBuffer to metal texture error")
}
if let image = sourceImageBuf {
sharedContext.metalTexture = CVMetalTextureGetTexture(image)
}
}
}
extension MetalTexture: FlutterTexture {
func copyPixelBuffer() -> Unmanaged<CVPixelBuffer>? {
if let pixelBuf = pixelBuf?.takeUnretainedValue() {
return Unmanaged.passRetained(pixelBuf)
} else {
return nil
}
}
}
外部使用的时候,需要将 sharedContext.metalTexture
绑定到需要展示的纹理上。
以上。