Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift include metal shader into library [Using swift package manager]

I've always worked with Xcode projects but now I'm starting a project that I want in the future run on other platforms, so I'm using Swift Package Manager to generate the project, but I'm facing an issue, my library need to include a metal shader file (also a openGL shader file), but I'm clueless on how to accomplish this.

My project has 2 parts, the library that holds the graphic stuff and the executable that is my actual application, so I want to import my graphic library into my application, but the issue is that the metal shader file is not included in the Xcode project also seems that isn't compiled/included in the bundled files for the library so I can load at runtime and use it when needed.

Also if you think I'm doing something completely wrong just point me.

Regards

like image 719
norman784 Avatar asked Jan 13 '18 19:01

norman784


1 Answers

In Xcode 12 (swift-tools-version:5.3) a .metal file can be used from within a Swift Package by using the MTLDevice.makeDefaultLibrary(bundle:) method.

The Swift Package should have a structure similar to:

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

The file MetalShaders.metal should contain the Metal source code, and the file MetalShaders.swift should contain the necessary setup code. One example for initial content of MetalShaders.swift is the following:

// 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 ...
    // 

}

With this approach, the packageMetalLibrary variable can then be accessed from the Xcode project that has a dependency on the Swift Package by importing the target from the swift package the same way that other frameworks or packages are imported.

import MetalShaders

It may be possible to use this approach with earlier versions of Xcode as the method MTLDevice.makeDefaultLibrary(bundle:) is available since iOS 10 / macOS 10.12, but the Bundle.module extension would need to be implemented and it is not clear if this will work.

like image 88
gmck Avatar answered Oct 12 '22 06:10

gmck