【问题标题】:How do you use MTLSharedTextureHandle or MTLSharedEventHandle with the C XPC interface on macOS?如何在 macOS 上将 MTLSharedTextureHandle 或 MTLSharedEventHandle 与 C XPC 接口一起使用?
【发布时间】:2018-11-13 17:04:41
【问题描述】:

TL;DR:您如何对MTLSharedTextureHandleMTLSharedEventHandler 进行编码和解码,使其可以通过xpc_dictionary 内的XPC 连接传输?


我正在开发的一个 macOS 应用程序广泛使用 XPC 服务,并使用基于 C 的 API 实现。 (即:xpc_main, xpc_connection, xpc_dictionary...)这在当时是有道理的,因为某些对象,如IOSurfaces,不支持NSCoding/NSSecureCoding,必须使用IOSurfaceCreateXPCObject 传递。

在 macOS 10.14 中,Apple 引入了用于在进程之间共享 Metal 纹理和事件的新类:MTLSharedTextureHandleMTLSharedEventHandle。这些类支持NSSecureCoding,但它们似乎在 C-XPC 接口中没有用于编码/解码它们的对应部分。

我想我可以使用[NSKeyedArchiver archivedDataWithRootObject:requiringSecureCoding:error] 之类的东西将它们转换为NSData 对象,然后可以将其存储在xpc_dictionary 中,但是当我尝试这样做时,出现以下异常:

Caught exception during archival: 
This object may only be encoded by an NSXPCCoder.

(NSXPCCoder 是一个私有类。)

MTLSharedTextureHandleMTLSharedEventHandle 都会发生这种情况。我可以切换到使用新的NSXPCConnection API,但我已经在 C 接口上构建了大量代码,所以我宁愿不必进行切换。

有没有办法将这两个类中的任何一个归档到一个有效负载中,该有效负载可以存储在xpc_dictionary 中,以便在服务和客户端之间传输?

【问题讨论】:

  • 如果您只是尝试将共享句柄对象视为 XPC 对象会发生什么?例如,将其存储在 XPC 字典等中?
  • 如果我将 MTLSharedTextureHandle 转换为 xpc_object_t 然后调用 xpc_dictionary_set_value,它只会在调用 xpc_connection_send_message 时崩溃。堆栈跟踪以 EXC_BAD_ACCESS(代码=EXC_I386_GPFLT)在 _xpc_dictionary_serialize_apply 结束。

标签: objective-c macos metal xpc nsxpcconnection


【解决方案1】:

MTLSharedTextureHandle 仅适用于 NSXPCConnection。如果您从 IOSurface 创建纹理,则可以共享该表面,这实际上是同一件事。确保您在两个进程中使用相同的 GPU(相同的 id<MTLDevice>)。

MTLSharedEventHandle 没有使用公共 API 的解决方法。

如果可以的话,我建议切换到NSXPCConnection。不幸的是,使用公共 API 进行部分转换并不是一个好故事,您必须一次完成所有操作,或者将您的 XPC 服务拆分为两个独立的服务。

【讨论】:

  • 感谢拉斯的洞察力。如果共享纹理是 IOSurface 的包装器,我是否可以通过渲染到服务中的共享纹理然后在应用程序中从该纹理进行 blit' 处理而不是渲染到服务中的 IOSurface 并将其发送到应用程序来获得任何东西,把它包裹在一个新的纹理中,然后从那个纹理中粘贴?我看到的唯一额外步骤是必须用纹理包裹 IOSurface 才能在应用程序端使用 blit 编码器,但这似乎很快。 (我在服务中使用 Core Image 来渲染将被复制到应用程序中的纹理的图像。)
  • 应该没什么区别;关键是将其放入 IOSurface 中。如果您要在除CAMetalLayer 之外的其他地方渲染屏幕显示,那么我建议将CALayer.contents 属性设置为IOSurface,然后在修改表面时调用setContentsChanged。如果需要在屏幕上显示,则通过图层应用变换。这样可以避免任何 blitting;像素可以一直停留在 GPU 上。 (这取决于你在做什么)
  • 我正在构建一个自定义“图像视图”以使用 MTKView 显示图像。我使用 XPC 服务将图像解码为CIImage,然后使用CIContent 渲染为IOSurface。然后将表面发送到应用程序,将其包裹在MTLTexture 中,以便我可以将其内容粘贴到“主”纹理中。然后回收该表面。我试图了解什么是最有效的方法是让我从 XPC 服务获取渲染图像数据并进入应用程序端的纹理,然后我可以在我的着色器中读取它。
  • 我会将所有这些都推送到 XPC 服务中。应用程序唯一需要的是对它需要放在屏幕上的表面的引用。如果你真的需要 blit,那么在 XPC 服务中进行。一条获取主表面的初始消息,然后是每次 XPC 服务更新内容时的一条消息,以便应用可以戳图层。
  • 我曾尝试将所有内容都放入服务中,但我永远无法弄清楚如何正确地进行所有同步。如果我要渲染到服务中的表面,那么我最终需要将该表面传递给应用程序并将其包装在纹理中,以便我可以在片段着色器中对其进行采样。如果我立即将该表面回收回服务,那么在我的下一次渲染过程中,我可能没有任何数据可供片段着色器采样。这就是为什么我加入一个“主”纹理,以便服务始终可以从中采样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-08-24
  • 2019-03-16
  • 2022-11-02
  • 2018-07-02
  • 2017-06-03
  • 1970-01-01
  • 2017-04-16
相关资源
最近更新 更多