当我在一个XPC进程中写入IOSurface
,并且同时被用作主应用程序中MTLTexture
的后备存储时,我需要使用哪些API,并需要注意什么预防措施?
在我的XPC服务中,我有以下内容:
IOSurface *surface = ...;
CIRenderDestination *renderDestination = [... initWithIOSurface:surface];
// Send the IOSurface to the client using an NSXPCConnection.
// In the service, periodically write to the IOSurface.
在我的应用程序中,我有以下内容:
IOSurface *surface = // ... fetch IOSurface from NSXPConnection.
id<MTLTexture> texture = [device newTextureWithDescriptor:... iosurface:surface];
// The texture is used in a fragment shader (Read-only)
我有一个正在运行正常更新循环的
MTKView
。我希望我的XPC服务能够定期使用Core Image写入IOSurface
,然后由应用程序端的Metal渲染新内容。需要什么同步来确保这样做?双重或三重缓冲策略是一种,但对我来说并不适用,因为我可能没有足够的内存来分配2倍或3倍数量的表面。(上面的示例仅使用一个表面以清晰明了为例,但实际上我可能有数十个表面正在绘制。每个表面表示图像的一个瓷砖。图像可以像JPG / TIFF /等允许的那样大。) WWDC 2010-442谈到了
IOSurface
,并简要提到所有这些都“只是起作用”,但这是在OpenGL的上下文中,并没有提到Core Image或Metal。最初,我认为Core Image和/或Metal将调用
IOSurfaceLock()
和IOSurfaceUnlock()
来保护读写访问,但实际上似乎并非如此。 (并且IOSurfaceRef.h
头文件中的注释表明锁定仅用于CPU访问。)
如果我真的可以让Core Image的CIRenderDestination
任意写入IOSurface
,而我在应用程序的更新循环中从相应的MTLTexture
读取,那么这是否可能?如果是这样,那么如果绑定到IOSurface
的所有纹理共享同一视频内存,那么如何做到这一点,正如WWDC视频所述,如果在同一次传递期间发生读取和写入,那么表面的内容就会出现撕裂。
CIRenderTask waitUntilCompletedAndReturnError
会确保 Core Image 完成,但使用它需要在启动 Core Image 渲染时以某种方式阻止应用程序中的 Metal 渲染循环,然后在完成后取消阻止渲染循环。苹果的示例代码使用两个 IOSurface 来实现这一点,并要求服务不断地告诉应用程序可以从哪个表面读取。我想避免双重或三重缓冲以减少内存开销。MTLSharedEventHandle
看起来很有前途,但它只适用于 10.14+,而且文档非常薄弱... - kennycmacOS
上,XPC服务有一个单独的CIImage
,可以表示非常大的图像。IOSurface
和MTLTexture
都限制在每边约16,384个像素,因此我通过创建多个表面来平铺图像,然后使用Core Image的能力将特定区域渲染到瓷砖表面上。有足够的表面加载到内存中以表示完整分辨率的图像。当我需要在应用程序的MTKView
中绘制其中一个或多个表面时,我将它们包装在Metal纹理中,并复制到可绘制对象中。这已被证明比使用Core Image实时绘制瓷砖要快得多。 - kennyc