Flutter+Metal实现图像处理

背景

在之前自制的图像处理App中,使用了OpenGL处理图片,这次使用Metal替代OpenGL,来达到更好的性能,顺便熟悉一下Metal的渲染流程

image.png

基本思路

Flutter使用CVPixelBuffer和iOS交互,我们可以直接使用CVPixelBuffer创建MTLTexture,然后将MTLTexture设置为渲染目标。这样Metal框架可以直接将渲染结果写入CVPixelBuffer,达到更加高效的目的。

Metal环境设置

主要初始化DevicePipelineStateCommandQueue三个对象。我们需要依赖Device分配各种Metal资源,PipelineState管理着渲染流水线的各个环节的配置,比如vertex shader,fragment shader,输出像素格式等。CommandQueue用于管理执行的绘制命令。

  1. _device = MTLCreateSystemDefaultDevice();
  2. id<MTLLibrary> lib = [_device newDefaultLibrary];
  3. id<MTLFunction> vertexFunc = [lib newFunctionWithName:vertexFuncName];
  4. id<MTLFunction> fragFunc = [lib newFunctionWithName:fragFuncName];
  5. MTLRenderPipelineDescriptor *renderPipelineDesc = [MTLRenderPipelineDescriptor new];
  6. renderPipelineDesc.vertexFunction = vertexFunc;
  7. renderPipelineDesc.fragmentFunction = fragFunc;
  8. renderPipelineDesc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
  9. _pipelineState = [_device newRenderPipelineStateWithDescriptor:renderPipelineDesc error:nil];
  10. _commandQueue = [_device newCommandQueue];

从CVPixelBuffer创建MTLTexture纹理

首先创建一个CVPixelBuffer对象

  1. NSDictionary *pixelAttributes = @{( id )kCVPixelBufferIOSurfacePropertiesKey : @{}};
  2. CVPixelBufferCreate(
  3. kCFAllocatorDefault,
  4. imageWidth,
  5. imageHeight,
  6. kCVPixelFormatType_32BGRA,
  7. (__bridge CFDictionaryRef)pixelAttributes,
  8. &_renderTargetPixelBuffer);

利用CVMetalTextureCacheCreateTextureFromImageCVPixelBuffer创建MTLTexture

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

渲染到纹理

CommandQueue获得一个CommandBuffer,用于保存需要执行的绘制命令

  1. _activeCmdBuffer = [_commandQueue commandBuffer];

创建MTLRenderPassDescriptor设置本次绘制的相关配置,比如绘制到哪里,这里指定通过CVPixelBuffer创建出来的MTLTexture,是否清除当前内容,清除的颜色

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

通过CommandBufferMTLRenderPassDescriptor创建一个MTLRenderCommandEncoder

  1. _activeEncoder = [_activeCmdBuffer renderCommandEncoderWithDescriptor:renderPassDesc];

指定MTLRenderCommandEncoder所在的PipelineState

  1. [_activeEncoder setRenderPipelineState:_pipelineState];

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

  1. [_activeEncoder setVertexBuffer:vertexBuffer offset:0 atIndex:0];
  2. [_activeEncoder setFragmentBuffer:uniformBuffer offset:0 atIndex:0];
  3. [_activeEncoder setFragmentBuffer:texture offset:0 atIndex:0];

绘制图形

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

显式的结束MTLRenderCommandEncoder

  1. [_activeEncoder endEncoding];

提交CommandBuffer

  1. [_activeCmdBuffer commit];

等待绘制结束,如果你想要异步等待,需要在[_activeCmdBuffer commit]之前设置completedHandler

  1. // 同步等待
  2. [_activeCmdBuffer waitUntilCompleted];
  3. // 异步等待
  4. [_activeCmdBuffer addCompletedHandler:^(id<MTLCommandBuffer> _Nonnull buf) {
  5. }];

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


文章标签:

原文连接:https://juejin.cn/post/7109838824569569294

相关推荐

看完这篇,你也可以搞定有趣的动态曲线绘制

Flutter 绘制探索 | 箭头端点的设计

极简的成本实现Flutter静态资源多渠道定制

Flutter 小技巧之优化使用的 BuildContext

Flutter ConstraintLayout(约束布局)完全指南

Flutter 2 商城App实战指南(支持Null safety)

利用Flutter开发了一个类似微信可运行小程序的App

为什么说 Compose 的声明式代码最简洁 ?Compose\u002FReact\u002FFlutter\u002FSwiftUI 语法对比

[Flutter] 认识Zone和异常处理

GetX状态管理的实现机制原理剖析

你真的敢落地Flutter桌面端吗?

Dart基本语法

Flutter Cupertino 教程:如何构建外观和感觉原生的 iOS 应用

【基于Flutter&Flame 的飞机大战开发笔记】展示面板及重新开始菜单

抢先体验! 在浏览器里写 Flutter 是一种什么体验?

由点汇聚成字的动效炫极了

【基于Flutter&Flame 的飞机大战开发笔记】利用bloc管理游戏状态

Flutter 绘制探索 | 来一起画箭头吧

【Flutter入坑】Mac + VS Code + Android真机环境搭建

【基于Flutter&Flame 的飞机大战开发笔记】子弹升级和补给