在XPC进程中写入IOSurface
时,我需要使用哪些API,以及需要采取哪些预防措施,XPC进程也用作主应用程序中MTLTexture
的后备存储?
在我的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访问。)
当我在应用程序的更新循环中读取相应的MTLTexture
时,我真的可以让Core Image的CIRenderDestination
随意写入IOSurface
吗?如果是这样,那么,正如WWDC视频所说,如果绑定到IOSurface
的所有纹理共享相同的视频内存,这怎么可能呢?如果阅读和写作同时进行,我肯定会对表面内容产生一些撕裂
您需要做的是确保在应用程序中使用IOSurface
绘制之前,CoreImage绘制已在XPC中完成。如果在两侧都使用OpenGL或Metal,则可以调用glFlush()
或[-MTLRenderCommandEncoder waitUntilScheduled]
。我认为CoreImage中的某个东西正在打这些电话。
我可以说,如果没有发生这种情况,这可能是显而易见的,因为如果事情没有正确同步,你会得到撕裂或一半是新渲染一半是旧渲染的图像。我在跨XPC使用IOSurface
时看到过这种情况。
您可以做的一件事是在-waitUntilScheduled
和-waitUntilCompleted
上放置一些符号断点,看看CI是否在XPC中调用它们(假设文档没有明确告诉您)。Metal中还有其他同步原语,但我对它们不是很熟悉。它们也可能有用。(据我所知,CI现在全是金属。)
此外,IOSurface
对象具有方法-incrementUseCount
、-decrementUseCount
和-localUseCount
。也许值得检查一下,看看CI是否对它们进行了适当的设置。(详见<IOSurface/IOSurfaceObjC.h>
。)