Как объединить командные кодеры рендеринга, которые используют другой шейдер в металле - PullRequest
2 голосов
/ 31 марта 2019

Я пишу графический движок на металле и использую буфер трафарета, чтобы маскировать объемы, покрытые сферическими гармоническими огнями в сцене.Для этого я использую два шейдера, и мне нужно 3 вызова отрисовки на источник света: один для задних граней, другой для лицевых граней и окончательный вызов отрисовки с другим шейдером для фактического рендеринга источника света.

НоЕсли я хорошо понимаю документацию по Metal, вам нужно определить все ваши проходы «статически», то есть вам нужен отдельный кодировщик команд рендеринга для каждого используемого вами шейдера и конфигураций рендеринга поверхностей.Это правильно?

Это означает, что я закончил тем, что создал этот цикл для своих источников света, который кажется ужасным, потому что я создаю много кодеров,

for l in shLights {
    let descStencil = createLightAccumulationRenderPass()
    guard let encoderStencil = commandBuffer.makeRenderCommandEncoder(descriptor: descStencil) else {
        continue
    }
    drawSHLightStencil(l, encoder: encoderStencil)
    encoderStencil.endEncoding()
    let descColor = createLightAccumulationRenderPass()
    guard let encoderColor = commandBuffer.makeRenderCommandEncoder(descriptor: descColor) else {
        continue
    }
    drawSHLight(l, encoder: encoderColor)
    encoderColor.endEncoding()
}

Полный код здесь: https://github.com/endavid/VidEngine/blob/master/VidFramework/VidFramework/sdk/gfx/plugins/DeferredLightingPlugin.swift (drawSHLights функция)

И если вам нужно больше контекста о том, как это используется, пожалуйста, проверьте этот блог: http://endavid.com/index.php?entry=85

Я также попытался повторно использоватькодировщики, но если вы не вызываете endEncoding, Металл падает при следующем вызове makeRenderCommandEncoder.

Возможно ли объединить эти кодировщики каким-либо образом?

Редактировать: IЯ сделал снимок с графического процессора, чтобы было легче увидеть весь конвейер рендеринга.Вот скриншот:

GPU capture

Это довольно маленький, но я поместил несколько ярлыков сверху.Белые метки соответствуют материалу в цикле.В сцене есть 3 источника света, и они освещают 3 сферы.

1 Ответ

3 голосов
/ 01 апреля 2019

Но, если я хорошо понял документацию по Metal, вам нужно определить все ваши проходы «статически», то есть вам нужен отдельный кодировщик команд рендеринга для каждого используемого вами шейдера и конфигураций поверхностей рендеринга.Это правильно?

Нет, это не совсем правильно.Вы заметите, что есть некоторые атрибуты кодировщика команд рендеринга, которые задаются через MTLRenderPassDescriptor во время создания кодировщика, а также есть другие атрибуты, которые устанавливаются через аксессоры на кодировщике после его создания.Первые являются неизменными на протяжении всего времени работы кодера.Последнее может быть изменено.

Итак, вам нужен новый кодировщик команд, если вы измените цели рендеринга (вложения).Но вам не нужен новый кодировщик команд для смены шейдеров.Шейдеры определяются состоянием конвейера рендеринга и могут быть изменены в существующем кодировщике команд с помощью setRenderPipelineState(_:).

Это действительно верно, что вы должны создавать ваши объекты состояния конвейера рендеринга один раз ввремя жизни приложения, если это вообще возможно.Но после этого вы можете использовать их так часто, как это необходимо.

Наконец, я бы не стал слишком беспокоиться о создании нескольких кодировщиков команд рендеринга.Они разработаны, чтобы быть относительно дешевыми в создании.Поэтому, хотя и стоит потратить немного усилий на консолидацию всей работы, которую можно выполнить вместе с данным кодировщиком, не стоит наклоняться назад, чтобы попытаться сделать что-то «более простое», когда оно идет вразрез с принципами работы.

...