Flutter - Integrating Metal on iOS

Guoba
2 min readJan 2, 2024

--

In a Flutter project, when integrating Metal on the iOS side, I utilize the Texture to display the corresponding view. The specific invocation method is not elaborated here, whether through MethodChannel or ffi.

To achieve the display using Texture, it's necessary for the native side to inherit the FlutterTexture protocol and implement the method - (CVPixelBufferRef _Nullable)copyPixelBuffer;.

Below is the essential code snippet:

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
}
}
}

When used externally, it’s necessary to bind sharedContext.metalTexture to the texture you want to display.

That’s all.

--

--

Guoba
Guoba

Written by Guoba

0 Followers

会的不多

No responses yet