如何跨进程同步MTLTexture和IOSurface?

时间:2019-02-03 15:46:48

标签: macos metal core-image xpc iosurface

在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的所有纹理共享相同的视频内存,那怎么可能呢?如果在同一遍中进行读写操作,我肯定会撕裂表面的内容。

1 个答案:

答案 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>。)