Swift 将金属着色器包含到库中 [使用 Swift 包管理器]

nor*_*784 6 swift metal swift-package-manager

我一直在使用 Xcode 项目,但现在我正在启动一个我希望将来在其他平台上运行的项目,所以我使用 Swift Package Manager 来生成项目,但我面临一个问题,我的库需要包含一个金属着色器文件(也是一个 openGL 着色器文件),但我对如何实现这一点一无所知。

我的项目有 2 个部分,包含图形内容的库和作为我实际应用程序的可执行文件,所以我想将我的图形库导入我的应用程序,但问题是金属着色器文件不包含在 Xcode 项目中似乎也没有编译/包含在库的捆绑文件中,因此我可以在运行时加载并在需要时使用它。

另外,如果您认为我做错了什么,请指出我。

问候

小智 5

在 Xcode 12 (swift-tools-version:5.3) 中,可以通过使用 Swift 包中的方法使用 .metal 文件MTLDevice.makeDefaultLibrary(bundle:)

Swift 包的结构应类似于:

-Sources
    -MetalShaders
        -MetalShaders.metal
        -MetalShaders.swift
-Tests
    -MetalShadersTests
        -MetalShadersTests.swift

Run Code Online (Sandbox Code Playgroud)

该文件MetalShaders.metal应包含 Metal 源代码,并且该文件MetalShaders.swift应包含必要的设置代码。初始内容的一个示例MetalShaders.swift如下:

// A metal device for access to the GPU.
public var metalDevice: MTLDevice!

// A metal library.
public var packageMetalLibrary: MTLLibrary!

// Function to perform the initial setup for Metal processing on the GPU
public func setupMetal() {
    // Create metal device for the default GPU:
    metalDevice = MTLCreateSystemDefaultDevice()
    
    // Create the library of metal functions
    // Note: Need to use makeDefaultLibrary(bundle:) as the "normal"
    //       call makeDefaultLibrary() returns nil.
    packageMetalLibrary = try? metalDevice.makeDefaultLibrary(bundle: Bundle.module)

    // List the available Metal shader functions
    print(packageMetalLibrary.functionNames)

    //
    // ... add additional setup code here ...
    // 

}
Run Code Online (Sandbox Code Playgroud)

通过这种方法,packageMetalLibrary可以通过从 swift 包导入目标(与导入其他框架或包的方式相同),从依赖于 Swift 包的 Xcode 项目访问该变量。

import MetalShaders

Run Code Online (Sandbox Code Playgroud)

可以在早期版本的 Xcode 中使用此方法,因为该方法MTLDevice.makeDefaultLibrary(bundle:)自 iOS 10 / macOS 10.12 起可用,但Bundle.module需要实现扩展,并且尚不清楚这是否有效。


nig*_*ill 5

将您的Shaders.metal文件放入Metal目录中。然后将资源添加到您的目标Package.swift

.target(
   name: "TargetName",
   dependencies: [
     .product(name: "AnotherModule", package: "AnotherPackage")
   ],
   resources: [
     .copy("Metal/")
   ]
)
Run Code Online (Sandbox Code Playgroud)

现在您可以访问您的图书馆:

let url = Bundle.module.url(forResource: "Shaders", withExtension: "metal", subdirectory: "Metal")!
let source = try String(contentsOf: url)
let library = try device.makeLibrary(source: source, options: nil)
Run Code Online (Sandbox Code Playgroud)

或者甚至更好(但仅适用于单个着色器文件):

.target(
   name: "TargetName",
   dependencies: [
     .product(name: "AnotherModule", package: "AnotherPackage")
   ],
   resources: [
     .process("Metal/Shaders.metal")
   ]
)
Run Code Online (Sandbox Code Playgroud)

现在您可以访问您的图书馆:

let library = try device.makeDefaultLibrary(bundle: Bundle.module)
Run Code Online (Sandbox Code Playgroud)


nor*_*784 0

看来现在还做不到这一点。当找到解决方法或 Apple 修复此问题时,我会更新此内容。

https://bugs.swift.org/browse/SR-2866

编辑:我发现的一个临时解决方案是创建一个bash 脚本,该脚本编辑工作区设置以更改构建路径,然后将 metallib 文件编译/复制到可执行路径(尚未尝试查看如何通过以下方式分发库) SPM 或类似的东西,现在仅适用于同一文件夹中的代码(即 Sources/MyEngine <-(此文件夹具有金属着色器)、Sources/MyGame)。