Swift включает металлический шейдер в библиотеку [Используя менеджер пакетов Swift]

Я всегда работал с проектами Xcode, но теперь я начинаю проект, который хочу в будущем запускать на других платформах, поэтому я использую диспетчер пакетов Swift для создания проекта, но столкнулся с проблемой, моя библиотека нужно включить файл металлического шейдера (также файл шейдера openGL), но я не знаю, как это сделать.

Мой проект состоит из 2 частей: библиотеки, содержащей графические материалы, и исполняемого файла, который является моим фактическим приложением, поэтому я хочу импортировать свою графическую библиотеку в свое приложение, но проблема в том, что файл металлического шейдера не включен в проект Xcode. также кажется, что он не скомпилирован/не включен в комплект файлов для библиотеки, поэтому я могу загрузить его во время выполнения и использовать его при необходимости.

Также, если вы думаете, что я делаю что-то совершенно неправильно, просто укажите мне.

С уважением


person norman784    schedule 13.01.2018    source источник
comment
Я не уверен, понимаю ли я вашу проблему - я никогда не использовал диспетчер пакетов Swift. (1) Является ли ваша библиотека Swift целью Framework? (2) Нужен ли вам доступ к этим файлам шейдеров? (3) Можете ли вы превратить эти файлы в в пакет и вручную включить их в проект Xcode? Если вы ответили на все три вопроса «Да», я верю, что смогу вам помочь.   -  person dfd    schedule 13.01.2018
comment
(1) Библиотека Swift имеет тип по умолчанию (я думаю, может быть только динамической или статической, поэтому должна быть dylib или что-то в этом роде. (2) Металлический файл, я думаю, должен быть скомпилирован непосредственно в metallib, и вам не нужно чтобы ссылаться на него непосредственно в коде, просто настройте функцию вершины и функцию фрагмента в инициализации металла (MTLLibrary).(3) Ну, я не совсем уверен, останутся ли связанные файлы, если я воссоздам проект Xcode (при добавлении некоторых новая зависимость, мне нужно воссоздать проект Xcode (или, по крайней мере, я делаю это)   -  person norman784    schedule 13.01.2018
comment
Да... в общем, я показал свою неопытность в том, что ты делаешь. Я думал, что это было по-другому. У меня есть проекты (и фреймворки, которые я import) использую CIKernels, которые являются файлами кода GLSL. Когда это Framework, приложению просто нужно import. Похоже, я вам ничем не помогу, извините.   -  person dfd    schedule 13.01.2018
comment
Вы написали, что металлический файл, я думаю, должен быть скомпилирован непосредственно в metallib, и вам не нужно ссылаться на него непосредственно в своем коде, просто настройте функцию вершины и функцию фрагмента в инициализации металла (MTLLibrary. Итак, какой код ссылается на него? код в исполняемом файле, который должен выполнять инициализацию металла?   -  person Vadim Eisenberg    schedule 15.01.2018
comment
Это библиотека (игровой движок), и я хочу распространять ее через SPM, поэтому шейдер находится на игровом движке. Я только что обнаружил, что металлический шейдер скомпилирован в файл metallib, поэтому в итоге я создал сценарий bash, проверьте мой ответ для получения дополнительной информации, но я все еще не доволен результатами, но пока я все еще могу работать над проект, не беспокоясь об этом, позже я обязательно найду решение или кто-то другой предложит лучший подход.   -  person norman784    schedule 15.01.2018
comment
Стоит подумать о шаблоне проектирования. Потому что Metal предназначен для предварительной компиляции, и это сильно отличается от GLSL, где шейдеры по-прежнему являются сценариями, которые применяются во время выполнения. Ваш класс рендеринга также будет полностью отличаться от GLSL до Metal. А будущее GLSL на платформах Apple выглядит не столь радужно, значит, развертывание готовой библиотеки не зависит от платформ? Вы держите класс рендеринга и металлический шейдер (скомпилированные) вместе в своем комплекте и объявляете об их использовании при определении вашего MTLDevice.   -  person Ol Sen    schedule 13.07.2020


Ответы (4)


В Xcode 12 (swift-tools-version:5.3) файл .metal можно использовать из пакета Swift с помощью метода MTLDevice.makeDefaultLibrary(bundle:).

Пакет Swift должен иметь структуру, похожую на:

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

Файл 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 ...
    // 

}

При таком подходе к переменной packageMetalLibrary можно получить доступ из проекта Xcode, который зависит от пакета Swift, путем импорта цели из пакета swift таким же образом, как импортируются другие платформы или пакеты.

import MetalShaders

Возможно, этот подход можно использовать с более ранними версиями Xcode, поскольку метод MTLDevice.makeDefaultLibrary(bundle:) доступен, начиная с iOS 10/macOS 10.12, но необходимо реализовать расширение Bundle.module, и неясно, будет ли это работать.

person gmck    schedule 13.07.2020

Поместите файл Shaders.metal в каталог Metal. Затем добавьте ресурсы к вашей цели в Package.swift

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

Теперь вы можете получить доступ к своей библиотеке:

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)

Или даже лучше (но только для одного файла шейдера):

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

Теперь вы можете получить доступ к своей библиотеке:

let library = try device.makeDefaultLibrary(bundle: Bundle.module)
person nightwill    schedule 24.01.2021
comment
Это способ - person Alexandre Camilleri; 30.03.2021

let source = """

    #include <metal_stdlib>
    using namespace metal;

    struct Vertex {...
"""
let library = try device.makeLibrary(source: source options: nil)
print(library.functionNames)

Класс Metal позволяет создавать библиотеку шейдеров из String во время выполнения. https://developer.apple.com/documentation/metal/libraries Надеюсь, это поможет .

person scherv    schedule 01.11.2019
comment
пожалуйста, кратко объясните свой ответ - person Mr. Pyramid; 01.11.2019
comment
не здесь отредактируйте свой ответ и добавьте необходимое описание - person Mr. Pyramid; 01.11.2019

Кажется, что сейчас это невозможно сделать. Я обновлю это, когда найду обходной путь или Apple решит эту проблему.

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

Редактировать: временным решением, которое я нашел, было создание скрипта bash которые редактируют настройки рабочей области, чтобы изменить путь сборки, а затем скомпилировать/скопировать файл metallib в исполняемый путь (еще не пробовал, чтобы увидеть, как работает распространение библиотеки через SPM или что-то в этом роде, сейчас работает только с кодом в той же папке (т.е. Sources/MyEngine ‹- (эта папка содержит шейдер металла), Sources/MyGame).

person norman784    schedule 14.01.2018