У меня есть фреймворк iOS, использующий Metal; он устанавливает дескриптор конвейера следующим образом:
...
_metalVars.mtlLibrary = [_metalVars.mtlDevice newLibraryWithFile:libraryPath error:&error];
id <MTLFunction> vertexFunction = [_metalVars.mtlLibrary newFunctionWithName:@"vertexShader"];
id <MTLFunction> fragmentFunction = [_metalVars.mtlLibrary newFunctionWithName:@"fragmentShader"];
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
pipelineStateDescriptor.label = @"MyPipeline";
pipelineStateDescriptor.vertexFunction = vertexFunction;
pipelineStateDescriptor.fragmentFunction = fragmentFunction;
pipelineStateDescriptor.vertexDescriptor = mtlVertexDescriptor;
pipelineStateDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormatRGBA8Unorm;
_metalVars.mtlPipelineState = [_metalVars.mtlDevice newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error];
...
Этот фреймворк используется приложением для iOS и работал нормально, пока не был установлен флажок
-fcikernel
был установлен под другими флагами металлического компилятора, и
-cikernel
в разделе «Другие флаги металлического компоновщика» в настройках сборки клиентского приложения. (флаги установлены на клиенте, согласно https://developer.apple.com/documentation/coreimage/cikernel/2880194-kernelwithfunctionname.)
С этими изменениями в клиентском приложении приведенный выше фрагмент кода фреймворка теперь дает сбой в последней строке приведенного выше фрагмента кода при вызове newRenderPipelineStateWithDescriptor
с ошибкой
validateWithDevice:2556: failed assertion `Render Pipeline Descriptor Validation
vertexFunction must not be nil
и я проверил, что фреймворк теперь возвращает nil для вершинной функции в
id <MTLFunction> vertexFunction = [_metalVars.mtlLibrary newFunctionWithName:@"vertexShader"];
но отлично работает, если я удалю флаги в клиентском приложении.
Вопросы: 1.) Я так понял, что металлические шейдеры были предварительно скомпилированы; почему изменение параметра сборки в клиентском коде может привести к сбою во время выполнения в неизменной среде? 2.) Как это можно решить?
Эти флаги предназначены для использования при компиляции ядер Core Image, написанных на Metal. Они изменяют способ перевода кода таким образом, что он несовместим с «обычным» кодом шейдера Metal.
Проблема с установкой флагов Core Image на уровне проекта заключается в том, что затрагиваются все файлы .metal
, независимо от того, содержат ли они ядра Core Image или обычный код шейдера.
Лучший способ обойти это — использовать другое расширение файла для файлов, содержащих ядра Core Image Metal, например .ci.metal
. Затем можно использовать специальные правила сборки для компиляции этих ядер отдельно от остальной части кодовой базы Metal.
Я рекомендую эту сессию с WWDC 2020, в которой подробно описан процесс.
Идеально - это исправило.