6

在写入同时用作主应用程序中IOSurface的后备存储的 XPC 进程中时,我需要使用哪些 API,需要采取哪些预防措施?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 服务能够定期写入IOSurface使用的 Core Image,然后让 Metal 在应用程序端呈现新内容。

需要什么同步来确保正确完成?双重或三重缓冲策略是一种,但这对我来说并不适用,因为我可能没有足够的内存来分配 2 倍或 3 倍的表面数量。(上面的例子为了清晰起见使用了一个表面,但实际上我可能有几十个表面我正在绘制。每个表面代表图像的一个平铺。图像可以像 JPG/TIFF/etc 允许的那样大。)

WWDC 2010-442 谈到IOSurface并简要提到这一切都“正常工作”,但这是在 OpenGL 的上下文中,并没有提到 Core Image 或 Metal。

我最初认为 Core Image 和/或 Metal 会调用IOSurfaceLock()IOSurfaceUnlock()保护读/写访问,但事实并非如此。(头文件中的注释IOSurfaceRef.h表明锁定仅用于 CPU 访问。)

我真的可以让 Core Image 随意CIRenderDestination写入我从应用程序更新循环中IOSurface读取的相应内容吗?MTLTexture如果是这样,那么如果正如 WWDC 视频所述,绑定到一个的所有纹理IOSurface共享相同的视频内存,那怎么可能呢?如果读取和写入发生在同一个通道中,我肯定会撕裂表面的内容。

4

1 回答 1

4

您需要做的是确保 CoreImage 在 XPC 中绘制完成,然后再IOSurface用于在应用程序中绘制。如果您在两边都使用 OpenGL 或 Metal,您可以调用glFlush()[-MTLRenderCommandEncoder waitUntilScheduled]. 我会假设 CoreImage 中的某些东西正在发出这些调用之一。

我可以说,如果没有发生这种情况可能会很明显,因为如果事情没有正确同步,你会得到撕裂或一半新渲染和一半旧渲染的图像。我已经看到在IOSurface跨 XPC 使用 s 时会发生这种情况。

您可以做的一件事是放置一些符号断点-waitUntilScheduled-waitUntilCompleted查看 CI 是否在您的 XPC 中调用它们(假设文档没有明确告诉您)。Metal 中还有其他同步原语,但我对它们不是很熟悉。它们也可能有用。(据我了解,CI 现在是引擎盖下的所有金属。)

此外,该IOSurface对象具有方法-incrementUseCount-decrementUseCount-localUseCount。可能值得检查这些以查看 CI 是否正确设置了它们。(详情请参阅<IOSurface/IOSurfaceObjC.h>。)

于 2019-02-03T19:32:50.733 回答