金属文件作为iOS框架的一部分

Doc*_*Noc 10 ios metal arkit

我正在尝试创建一个适用于METAL Api(iOS)的框架.我是这个平台的新手,我想知道如何构建框架来处理.metal文件(我正在构建一个静态库,而不是动态的).它们应该是.a文件的一部分,还是作为框架包中的资源文件?或者还有其他方法吗?谢谢.

更新: 对于那些解决这个问题的人 - 我最终关注了warrenm的1建议选项 - 将.metal文件转换为字符串并调用newLibraryWithSource:options:error:.虽然它不是性能最好的,但它允许我只发送一个框架文件,而无需导入额外的资源.对于使用着色器文件创建使用Metal,ARKit等的框架的人来说,这可能很有用.

war*_*enm 16

有许多方法可以为Metal着色器提供静态库,所有这些都有不同的权衡.我会试着在这里列举它们.

1)将.metal文件转换为静态字符串,这些字符串将被烘焙到静态库中.

这可能是最糟糕的选择.我们的想法是将您的Metal着色器代码预处理为字符串,这些字符串作为字符串文字包含在静态库中.然后,您将使用newLibraryWithSource:options:error:API(或其异步兄弟)将源转换为MTLLibrary并检索函数.这需要您设计一个进行.metal字符串转换的过程,并且您失去了着色器预编译的好处,使得生成的应用程序变慢.

2)将.metal文件与静态库一起发送,并要求库用户将它们添加到其应用目标

考虑到所有这些,这是一个不错的选择,虽然它会给你的用户带来更多的负担并暴露你的Metal着色器源(如果这是一个问题).静态库中的代码可以使用"默认库"(newDefaultLibrary),因为代码将由Xcode自动编译到应用程序中default.metallib,该应用程序作为资源嵌入到应用程序包中.

3)将.metallib文件与静态库一起发送

这是易用性,性能和安全性之间的良好中间点(因为它不会暴露您的着色器源,只会暴露其IR).基本上,您可以在项目中创建一个"金属库"目标,并将着色器代码放入其中.这将生成一个.metallib文件,您可以将其与静态库一起发布,并将您的用户作为资源嵌入其应用目标中.您的静态库可以.metallib使用newLibraryWithData:error:newLibraryWithURL:error:API 加载运行时.由于您的着色器将被预编译,因此创建库将更快,并且您将保持编译时诊断的好处.


Jim*_*tin 7

当有人希望在SceneKit / ARKit相关框架中包含金属着色器功能时,可用的答案将我引向错误的方向。有一个更简单的解决方案,使用makeDefaultLibrary(bundle:Bundle)(iOS 10+)访问框架.metal依赖项中包含的功能。为类似位置的人添加此处。

TL; DR,像这样访问框架的MTLLibrary:

        //Get the framework bundle by using `Bundle(for: type(of: self))` from inside any framework class.
        //Then use the bundle to define an MTLLibrary.
        let frameworkBundle = Bundle(for: type(of: self))
        let device = MTLCreateSystemDefaultDevice()
        do {
            let bundleLib = try device?.makeDefaultLibrary(bundle: frameworkBundle)
            print(bundleLib.functionNames) //we can access our framework's metal functions! No build tricks/workarounds.
        } catch {
            print("Couldn't locate default library for bundle: \(frameworkBundle)")
            print( error )
        }
Run Code Online (Sandbox Code Playgroud)

Xcode在编译时通过编译.metal依赖关系来创建默认的着色器函数库。框架目标和应用程序目标都是如此,所以真正的问题是,如何访问框架的默认库?

使用上的makeDefaultLibrary(bundle: Bundle)方法可以访问框架的默认库MTLDevice。上面的示例代码显示了更多细节。

对于带有SCNProgram的Scenekit / ARKit

可以将bundle库设置为SCNProgram的library属性,然后可以定义片段和着色器函数,就像主项目中包括.metal文件一样:

        //The SCNProgram that will use our framework's metal functions
        var program = SCNProgram()

        //Use the framework's bundle to define an MTLLibrary.
        let frameworkBundle = Bundle(for: type(of: self))
        let device = MTLCreateSystemDefaultDevice()
        do {
            let bundleLib = try device?.makeDefaultLibrary(bundle: frameworkBundle)

            //set the SCNProgram's library, and define functions as usual
            program.library = bundleLib
            program.fragmentFunctionName = "yourCustomFrameworkFragmentFunction"
            program.vertexFunctionName = "yourCustomFrameworkVertexFunction"
        } catch {
            print("Couldn't locate default library for bundle: \(frameworkBundle)")
            print( error )
        }
Run Code Online (Sandbox Code Playgroud)