在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 / etc允许。)
WWDC 2010-442讨论了IOSurface
,并简要提到了这一切都是“可行的”,但这是在OpenGL的上下文中,没有提及Core Image或Metal。
我本来以为Core Image和/或Metal将调用IOSurfaceLock()
和IOSurfaceUnlock()
来保护读/写访问,但事实并非如此。 (而且IOSurfaceRef.h
头文件中的注释表明锁定仅用于CPU访问。)
当我在应用程序的更新循环中从相应的CIRenderDestination
读取内容时,我真的可以让Core Image的IOSurface
随意写到MTLTexture
吗?如果是这样,那么,如WWDC视频所声明的那样,如果绑定到IOSurface
的所有纹理共享相同的视频内存,那怎么可能呢?如果在同一遍中进行读写操作,我肯定会撕裂表面的内容。
答案 0 :(得分:0)
您需要做的是确保在使用IOSurface
绘制应用程序之前,在XPC中完成CoreImage绘制。如果双方都使用OpenGL或Metal,则可以调用glFlush()
或[-MTLRenderCommandEncoder waitUntilScheduled]
。我认为CoreImage中的某项正在进行这些调用之一。
我可以说,如果没有发生,这很可能会很明显,因为如果没有正确同步,您会流泪,或者图像是新渲染的一半,而旧渲染的一半。我已经看到在XPC中使用IOSurface
时会发生这种情况。
您可以做的一件事是在-waitUntilScheduled
和-waitUntilCompleted
上放置一些符号断点,并查看CI是否在XPC中调用它们(假设documentation没有明确告诉您) 。 Metal中还有其他同步原语,但是我对它们并不十分熟悉。它们也可能有用。 (据我了解,CI现在全都是金属了。)
此外,IOSurface
对象具有方法-incrementUseCount
,-decrementUseCount
和-localUseCount
。可能值得检查这些内容,以查看CI是否对其进行了适当设置。 (有关详细信息,请参见<IOSurface/IOSurfaceObjC.h>
。)