MTLBlitCommandEncoder в AVCaptureSession неправильно отображает изображение. Должен ли я использовать функцию шейдера отображения?

При рисовании изображений в MKTView, MTLBlitCommandEncoder кажется хорошей идеей, так как мы можем просто скопировать текстуру в currentDrawable из MKTView. Код намного короче, чем MTLComputeCommandEncoder/MTLRenderCommandEncoder, которые запрашивают pipelineState и descriptor.

Однако мой код ниже не отображает изображение должным образом, для (я думаю) разных размеров входной текстуры и выходной. Любые советы или предложения по использованию MTLBlitCommandEncoder в таком случае? Или мне нужно использовать функцию шейдера, как мы видим в посте ниже/git?

Отображение изображения JPEG с помощью MTKView

https://github.com/navoshta/MetalRenderCamera

func draw(in view: MTKView) {
  guard let drawable = view.currentDrawable else {return}
  guard let commandBuffer = commandQueue.makeCommandBuffer() else {fatalError()}
  guard let blitEncoder = commandBuffer.makeBlitCommandEncoder() else{fatalError()}
  guard let texture = self.texture else {fatalError()}
  let targetW = min(texture.width, drawable.texture.width)
  //720, 1125 in my case
  let targetH = min(texture.height, drawable.texture.height)
  //1280, 2436

  blitEncoder.copy(from: texture, sourceSlice: 0, sourceLevel: 0, sourceOrigin: MTLOrigin(x: 0, y: 0, z: 0), sourceSize: MTLSizeMake(targetW, targetH, texture.depth), to: drawable.texture, destinationSlice: 0, destinationLevel: 0, destinationOrigin: MTLOrigin(x: 0, y: 0, z: 0))
  blitEncoder.endEncoding()
  commandBuffer.present(drawable)
  commandBuffer.commit()
  commandBuffer.waitUntilCompleted()
}

Заранее благодарим за вашу помощь.


person Giraff Wombat    schedule 05.02.2019    source источник
comment
Имеют ли две текстуры одинаковый формат пикселей? Одинаковое количество образцов? Они сжаты? Вы пробовали работать с включенной проверкой металла? Это вызывает утверждение?   -  person Ken Thomases    schedule 05.02.2019
comment
Привет Кен, спасибо за ваш комментарий. FPS такой же 30. Metal Validation не выдает предупреждений. Пиксельный формат — bgra8Unorm в mtkView.colorPixelFormat и CVMetalTextureCacheCreateTextureFromImage. Но активный формат устройства — kCVPixelFormatType_420YpCbCr8BiPlanarFullRange. Это проблема?   -  person Giraff Wombat    schedule 06.02.2019
comment
MTLPixelFormat не имеет 8bitYpCbCr, в то время как для устройства iPhone X доступны только форматы 420YpCbCr.   -  person Giraff Wombat    schedule 06.02.2019
comment
Важно, чтобы texture.pixelFormat и drawable.texture.pixelFormat совпадали. В противном случае метод copy(...) не сработает. Учитывая, что формат пикселей Core Video — YpCbCr, кажется вероятным, что текстура на самом деле не содержит данных RGB (или BGR), а bgra8Unorm просто используется, потому что нет ничего лучше. Кроме того, поскольку он плоский, вероятно, есть несколько текстур или, возможно, срезов. Вы можете попробовать изучить текстуру в отладчике кадров графического процессора Xcode. Вам, вероятно, потребуется преобразовать данные тем или иным образом. Шейдер кажется разумным подходом.   -  person Ken Thomases    schedule 06.02.2019
comment
Большое спасибо, Кен. Кажется, мне нужно скрыть/извлечь данные, тогда шейдер + renderCommandEncoder будет простым.   -  person Giraff Wombat    schedule 06.02.2019
comment
Вы должны использовать YpCbCr с камеры? Если нет, проще сказать камере, чтобы вместо этого выдавали вам данные BGRA.   -  person Matthijs Hollemans    schedule 06.02.2019
comment
Привет Маттис. Да, ты прав. Я установил kCVPixelFormatType_32BGRA в настройках вывода видео. Но это не решило проблему размера. В итоге я использовал MPSImageLanczosScale, чтобы настроить входную текстуру на drawable.texture. Я предполагаю, что это лучшее/простое решение, когда вы помещаете буферы сэмплов CaptureSession в mtkview.   -  person Giraff Wombat    schedule 07.02.2019
comment
Блит — это просто копия, она будет работать только с тем же форматом пикселей и одинаковой шириной и высотой в src и dst. Если вы хотите изменить размер, то требуется вызов масштабирующего шейдера. Вы также должны убедиться, что ваши пиксельные данные BGRA представлены как пиксели sRGB, чтобы масштабирование могло правильно интерпретировать значения пикселей, поступающие с камеры, как sRGB с гамма-кодированием, а не как прямые линейные значения. Вы можете найти рабочий исходный код для этого с помощью Metal в этом проекте github: github.com/mdejong/MetalBT709Decoder   -  person MoDJ    schedule 15.02.2019