Несколько советов по работе с ядрами MPS в целом и фильтрами пирамид изображения в частности:
- Если вы собираетесь использовать ядро более одного раза, кэшируйте его ииспользуйте его вместо того, чтобы создавать ядро каждый раз, когда вам нужно кодировать.
- Попробуйте установить для свойства
edgeMode
ядра значение .clamp
при понижающей дискретизации, поскольку выборка выходит за пределы (как это делает пирамида Гаусса)на первом шаге) по умолчанию вернет черный и введет искусственно темные пиксели. - При кодировании ядра гауссовой пирамиды всегда используйте метод «на месте», не предоставляя запасной распределитель:
kernel.encode(commandBuffer: commandBuffer, inPlaceTexture: &myTexture)
Как вы заметили, запуск ядра пирамиды изображений приводит к получению доступных уровней mip понижаемой дискретизации текстуры.Это означает, что для текстуры, которую вы предоставляете, уже должно быть выделено столько уровней mip, сколько вы хотите заполнить.Таким образом, вы должны убедиться, что дескриптор, который вы используете для создания вашей текстуры, имеет соответствующий mipmapLevelCount
(это обеспечивается вспомогательным методом texture2DDescriptorWithPixelFormat
и может управляться косвенно с помощью опции .allocateMipmaps
с MTKTextureLoader
).
Предполагая, что теперь вы знаете, как кодировать ядро и получить желаемые результаты в вашей текстуре, вот несколько ответов на ваши вопросы:
1.Как можно получить доступ к изображениям с mip-отображением после применения фильтра?
Вы можете неявно использовать mipmaps в шейдере при рендеринге с использованием сэмплера, который имеет фильтр mip, или вы можете явно сэмплироватьот определенного уровня MIP путем передачи параметра lod_option
типа level
в функцию sample
:
constexpr sampler mySampler(coord::normalized, filter::linear, mip_filter::linear);
float4 color = myTexture.sample(mySampler, texCoords, level(selectedLod))
Это работает в вычислительных ядрах, а также в функциях рендеринга.Используйте MIP-фильтр nearest
или округляйте выбранный LOD, если вы хотите производить выборку с одного уровня MIP, а не трилинейную MIP-фильтрацию.
2.Можно ли скопировать изображения с mip-отображением в другое изображение для обработки?
Поскольку текстура, которая подвергается понижающей дискретизации ядром пирамиды изображений, уже должна иметь флаг использования .pixelFormatView
, вы можете создать просмотр текстуры для текстуры с переворотом, которая выбирает один или несколько уровней.Например, если вы хотите выбрать первый и более высокий уровни MIP (отбрасывая базовый уровень), вы можете сделать это следующим образом:
let textureView = myTexture.makeTextureView(pixelFormat: myTexture.pixelFormat,
textureType: myTexture.textureType,
levels: Range<Int>(uncheckedBounds: (1, myTexture.mipmapLevelCount)),
slices: Range<Int>(uncheckedBounds: (0, 1)))
Вы также можете использовать кодировщик команды blit для копирования из одной текстурык другому, указав, какие уровни MIP для включения.Это позволяет освободить исходную текстуру, если вы хотите восстановить память, используемую нижними уровнями mip.
Вы можете обернуть MTLTexture
в MPSImage
, если хотите использовать API, которые работают с изображениямиа не текстуры:
let image = MPSImage(texture: myTexture, featureChannels: 4)
3.Будет ли это растровое изображение быстрее, чем создание пирамиды вручную с помощью пользовательских фильтров?
Почти наверняка.Шейдеры Metal Performance настроены для каждого поколения устройств и имеют многочисленные эвристические параметры, которые оптимизируют скорость выполнения и использование энергии.