是否有可能直接将 C++ 与 Metal API 一起使用

Posted

技术标签:

【中文标题】是否有可能直接将 C++ 与 Metal API 一起使用【英文标题】:Is there any possibility of using C++ directly with Metal API 【发布时间】:2015-03-15 08:02:13 【问题描述】:

由于 Metal Language 也是基于 C++11,而 C++ 似乎是一种经过验证的性能语言的完美契合,我希望完全绕过 Objective-C / Swift。我很想留在 C++ 领域。有没有可能?

【问题讨论】:

【参考方案1】:

技术上是的,但它会非常难看,并且可能会破坏其他一些 Objective-C 部分。

Objective-C 与 C++ 一样,是作为预处理器开始的。其中一个遗留问题是,每个 Objective-C 方法也公开为 C 函数调用,该函数调用分别将对象实例和方法选择器作为前两个参数,然后以从左到右的顺序声明其他参数。

NSObject 和构成 Objective-C 运行时的 C 调用都可以查找将被任何方法调用调用的当前 C 函数。

因此,您可以创建一个 C++ 类来获取所有 C 函数指针(它甚至可以从 C 运行时执行此操作,使其成为纯 C++ 代码而不是 Objective-C++)并直接跳转到类似的适当代码。

缺点是:Objective-C 通常使用动态分派(即在每次调用时将方法解析为 C 函数)和键值观察等机制仅因为它使用动态分派而起作用。如果您在其他人开始观察之前获取 C 函数指针,那么您的调用将在不通知观察者的情况下更新属性。所以你可能会破坏一些模块。

发出该警告,并假设您可以将 C++ 桥接类构建为 Objective-C++ 以获得更简单的语法,例如

class MTLArray 
    id m_instance;
    static NSUInteger (* s_arrayLength)(id object, SEL selector);
;

MTLArray::MTLArray() 
    // assuming you use the m_ pattern for instance variables
    m_instance = [MTLArray new];

    // assuming you use s_ for static variables; also pretending
    // the mapping from method to C function will never change —
    // KVO is the most prominent exception but otherwise you can
    // be exceedingly confident, albeit you'll be relying on
    // empirical behaviour, not the formal contract
    if(!s_arrayLength) 
        s_arrayLength = [MTLArray instanceMethodForSelector:@selector(arrayLength)];
    


NSUInteger MTLArray::getArrayLength() 
    return s_arrayLength(m_instance, @selector(arrayLength));

... 我很方便地拒绝将+instanceMethodForSelector: 的结果转换为适当的类型,因为我相信我会弄错。我倾向于退缩并在我的实际代码中引入中间 typedef,但您可能更喜欢更简洁。

【讨论】:

当然,通过实现这种危险的准静态调度,您可以避免一次调用 objc_msgSend,但 IMP 仍然指的是几乎肯定会调用其他 Objective-C 方法的函数。因此,我断言不可能按照 OP 的要求“完全绕过”Objective-C。 @warrenm 同意:这种方法 (i) 危险; (ii) 充其量是准静态的。但我很乐观,它产生的运行时点将使作者有足够的知识知道他在寻找什么;毕竟他是一个 C++/Metal 程序员,所以他显然对机器级的思想很满意。此外,我还想将其描述为保存对 objc_msgSend 的调用,就好像堆栈帧设置是成本一样——我假设他想要避免的是动态调度。你暗示你怀疑有什么意义,成本可以忽略不计。如果是这样,那么我同意。 这与他擅长操作的抽象级别无关,而与您的答案没有实际解决手头的问题有关。 @warrenm 手头的问题是“是否有可能[直接将 C++ 与 Metal API 一起使用]?”。如果您认为我的回答没有解决这个问题,那么我们不同意。 看来我们有不同的执着。您的答案集中在从 C++“直接”使用 Metal 上。即便如此,这也是一个糟糕的解决方案。你最好只用 Objective-C++ 类包装 Metal,因为绝对没有办法从等式中实际删除 Objective-C。我在强调“完全绕过”这个短语,这对我来说清楚地表明 OP 想要一个实际上完全绕过 Objective-C 的解决方案(即,获得 底层的 C 或 C++ 实现 i> Metal 的 Objective-C 外观)。在这方面,您的回答根本无法满足要求。【参考方案2】:

以下开源项目为 Metal 提供了 C++ 包装器:

https://github.com/naleksiev/mtlpp

【讨论】:

【参考方案3】:

没有。 Metal 仅作为 Objective-C API 公开。充其量,你可以用一组 Objective-C++ 类来包装它,但这只会增加开销,而不是像你想要的那样绕过 Objective-C。

【讨论】:

【参考方案4】:

如果您想使用 Objective-C API,但主要使用 C++ 工作,那么最好的选择是 Objective-C++。这只是 Objective-C,但使用 C++ 而不是 C 作为底层语言。

要将 Objective-C 类转换为 Objective-C++,只需将源文件的后缀从“.m”更改为“.mm”。 (您还需要确保在链接时包含正确的 C++ 运行时库。)

完成此操作后,您可以在 Objective-C 方法中使用 C++ 代码,包括像 std::vector 这样的模板类型以及像基于范围的 for 循环这样的 C++11 构造。

【讨论】:

以上是关于是否有可能直接将 C++ 与 Metal API 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

将纯 Metal-API 与 SceneKit 或 SpriteKit 一起使用

Metal - `include` 或 `import` 函数

使用Metal API与Imageblocks模板“隐式实例化”错误

将 Metal MTKView 实时捕获为电影?

METAL渲染是什么?

如何将 Metal Performance Shader 与 MTLBlitCommandEncoder 同步?