以非阻塞方式等待 CIContext 渲染任务

Posted

技术标签:

【中文标题】以非阻塞方式等待 CIContext 渲染任务【英文标题】:Wait on CIContext render tasks in a non-blocking way 【发布时间】:2021-05-26 08:56:14 【问题描述】:

我正在寻找一种方法来等待 CIContext 渲染完成而不会阻塞。为简单起见,这里有一个示例,我使用CIImageCIContext 将一个CVPixelBufferRef 渲染到另一个CVPixelBufferRef。显然我的实际管道会做得更多,但这是最简单的情况。

CIContext *context = [CIContext new];
// sourceBuffer provided from something like a camera
CIImage *image = [CIImage imageWithCVPixelBuffer:sourceBuffer];

CVPixelBufferRef output;
// pool was allocated elsewhere
CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, bufferPool, &output)
[context render:image toCVPixelBuffer:output];

代码在渲染完成之前一直阻塞,因为[CIContext render:toCVPixelBuffer:] 正在阻塞。

您可以使用[CIContext startTaskToRender:toDestination:error:] 以非阻塞方式启动渲染任务,就像这样

CIContext *context = [CIContext new];
// sourceBuffer provided from something like a camera
CIImage *image = [CIImage imageWithCVPixelBuffer:sourceBuffer];

CVPixelBufferRef output;
// pool was allocated elsewhere
CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, bufferPool, &output)

CIRenderDestination *destination = [[CIRenderDestination alloc] initWithPixelBuffer:output];
[context startTaskToRender:image toDestination:destination error:nil];

到了一半,调用没有阻塞,但是我不知道渲染任务什么时候完成。该 API 返回一个 CIRenderTask,但它只有一个实例方法,当然是 waitUntilCompletedAndReturnError,它会阻塞直到任务完成。

说实话,除了提供错误回调的媒介外,我并不真正理解这个 API 的意义。除非您的管道不需要知道任务何时完成,否则您仍然必须阻止才能获得结果。

那么,我的问题是:是否可以在不阻塞的情况下获得CIContext 渲染的结果?

【问题讨论】:

【参考方案1】:

第一个render 调用实际上不应该是阻塞调用。正如this answer中提到的,

“Core Image 延迟渲染,直到客户端请求访问帧缓冲区,即CVPixelBufferLockBaseAddress”。

但是,您也可以使用 CIRenderDestiantion API 并像这样自己使其异步:

CIRenderTask *task = [context startTaskToRender:image toDestination:destination error:nil];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^
    [task waitUntilCompletedAndReturnError: NULL];
    // do async stuff here, e.g. call a callback block
);

【讨论】:

这很有趣。在分析我的应用程序时,渲染行特别占我总 CPU 使用率的近 80%。看起来如果它只是推迟到下一次我需要锁定帧缓冲区时它会立即返回,并且 CPU 税将在下一个管道阶段(视频编码器)。

以上是关于以非阻塞方式等待 CIContext 渲染任务的主要内容,如果未能解决你的问题,请参考以下文章

Spring如何以非阻塞方式匹配bcrypt密码

同步异步,阻塞非阻塞,并发并行

如何以非阻塞方式处理 websocket 数据?

以非阻塞方式打开 QDialog

使用 Matplotlib 以非阻塞方式绘图

如何以非阻塞方式压缩文件