布景

在之前克己的图画处理App中,运用了OpenGL处理图片,这次运用Metal代替OpenGL,来抵达更好的功用,趁便了解一下Metal的烘托流程

Flutter+Metal实现图画处理

基本思路

Flutter运用CVPixelBuffer和iOS交互,咱们可以直接运用CVPixelBuffer创建MTLTexture,然后将MTLTexture设置为烘托方针。这样Metal结构可以直接将烘托效果写入CVPixelBuffer,抵达愈加高效的意图。

Metal环境设置

主要初始化DevicePipelineStateCommandQueue三个方针。咱们需求依赖Device分配各种Metal资源,PipelineState办理着烘托流水线的各个环节的配备,比方vertex shader,fragment shader,输出像素格局等。CommandQueue用于办理履行的制造指令。

_device = MTLCreateSystemDefaultDevice();
id<MTLLibrary> lib = [_device newDefaultLibrary];
id<MTLFunction> vertexFunc = [lib newFunctionWithName:vertexFuncName];
id<MTLFunction> fragFunc = [lib newFunctionWithName:fragFuncName];
MTLRenderPipelineDescriptor *renderPipelineDesc = [MTLRenderPipelineDescriptor new];
renderPipelineDesc.vertexFunction = vertexFunc;
renderPipelineDesc.fragmentFunction = fragFunc;
renderPipelineDesc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
_pipelineState = [_device newRenderPipelineStateWithDescriptor:renderPipelineDesc error:nil];
_commandQueue = [_device newCommandQueue];

从CVPixelBuffer创建MTLTexture纹路

首要创建一个CVPixelBuffer方针

NSDictionary *pixelAttributes = @{( id )kCVPixelBufferIOSurfacePropertiesKey : @{}};
CVPixelBufferCreate(
            kCFAllocatorDefault,
                    imageWidth,
                    imageHeight,
            kCVPixelFormatType_32BGRA,
                    (__bridge CFDictionaryRef)pixelAttributes,
                    &_renderTargetPixelBuffer);

使用CVMetalTextureCacheCreateTextureFromImageCVPixelBuffer创建MTLTexture

CVReturn ret = CVMetalTextureCacheCreate(kCFAllocatorDefault, nil, _mtContext.device, nil, &_textureCache);
CVMetalTextureRef renderTargetMetalTextureRef;
ret = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _textureCache, _renderTargetPixelBuffer, nil, MTLPixelFormatBGRA8Unorm, imageWidth, imageHeight, 0, &renderTargetMetalTextureRef);
id<MTLTexture> mtlTexture = CVMetalTextureGetTexture(renderTargetMetalTextureRef);

烘托到纹路

CommandQueue获得一个CommandBuffer,用于保存需求履行的制造指令

_activeCmdBuffer = [_commandQueue commandBuffer];

创建MTLRenderPassDescriptor设置本次制造的相关配备,比方制造到哪里,这儿指定通过CVPixelBuffer创建出来的MTLTexture,是否铲除当时内容,铲除的色彩

MTLRenderPassDescriptor *renderPassDesc = [MTLRenderPassDescriptor new];
renderPassDesc.colorAttachments[0].texture = target;
renderPassDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
renderPassDesc.colorAttachments[0].clearColor = MTLClearColorMake(0, 0, 0, 1);

通过CommandBufferMTLRenderPassDescriptor创建一个MTLRenderCommandEncoder

_activeEncoder = [_activeCmdBuffer renderCommandEncoderWithDescriptor:renderPassDesc];

指定MTLRenderCommandEncoder所在的PipelineState

[_activeEncoder setRenderPipelineState:_pipelineState];

运用MTLRenderCommandEncoder绑定BufferTexture,在Metal里,Uniform和Vertex Buffer 都是通过MTLBuffer绑定到Shader中

[_activeEncoder setVertexBuffer:vertexBuffer offset:0 atIndex:0];
[_activeEncoder setFragmentBuffer:uniformBuffer offset:0 atIndex:0];
[_activeEncoder setFragmentBuffer:texture offset:0 atIndex:0];

制造图形

[_activeEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:vertexCount instanceCount:1];

显式的结束MTLRenderCommandEncoder

[_activeEncoder endEncoding];

提交CommandBuffer

[_activeCmdBuffer commit];

等候制造结束,假如你想要异步等候,需求在[_activeCmdBuffer commit]之前设置completedHandler

// 同步等候
[_activeCmdBuffer waitUntilCompleted];
// 异步等候
[_activeCmdBuffer addCompletedHandler:^(id<MTLCommandBuffer> _Nonnull buf) {
}];

到此制造的内容就已经在CVPixelBuffer中了,再将CVPixelBuffer提交给Flutter显现即可