3

我正在使用 AVFoundation 来获取相机流。我正在使用此代码从以下位置获取 MTLTextures:

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
  CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);

  id<MTLTexture> texture = nil;

  {
    size_t width = CVPixelBufferGetWidth(pixelBuffer);
    size_t height = CVPixelBufferGetHeight(pixelBuffer);

    MTLPixelFormat pixelFormat = MTLPixelFormatBGRA8Unorm;

    CVMetalTextureRef metalTextureRef = NULL;

    CVReturn status = CVMetalTextureCacheCreateTextureFromImage(NULL, _textureCache, pixelBuffer, NULL, pixelFormat, width, height, 0, &metalTextureRef);
    if(status == kCVReturnSuccess)
    {
     texture = CVMetalTextureGetTexture(metalTextureRef);

     if (self.delegate){

        [self.delegate textureUpdated:texture];
      }
      CFRelease(metalTextureRef);
    }
  }
}

它工作正常,除了生成的MTLTexture对象没有 mipmaped(只有一个 mip 级别)。在本次通话中:

CVMetalTextureCacheCreateTextureFromImage(NULL, _textureCache, pixelBuffer, NULL, pixelFormat, width, height, 0, &metalTextureRef);

还有第三个参数称为“ textureAtributes ”,我认为可以指定我想要 mipmaped 纹理,但我在文档中没有找到任何字词到底是什么。我也没有找到传递其他内容而不是 NULL 的源代码。

iOS的OpenGLES中有类似的方法,具有相同的参数,并且文档中也没有文字。

4

2 回答 2

3

刚刚收到金属工程师的答复。这是一个报价:

不,不可能直接从 CVPixelBuffer 生成 mipmapped 纹理。
CVPixelBuffer图像通常具有线性/跨步布局,因为非 GPU 硬件块可能与它们进行交互,并且大多数 GPU 硬件仅支持来自平铺纹理的 mipmap。您需要发出 blit 以从线性MTLTexture复制到您自己创建的私有 MTLTexture ,然后生成 mipmap。

至于textureAttributes,只支持一个键:kCVMetalTextureCacheMaximumTextureAgeKey

于 2014-11-13T10:27:18.850 回答
1

没有直接获取 mipmap 纹理的方法,但您可以很容易地自己生成一个。

首先使用您的 Metal 设备创建一个空的 Metal 纹理,它的大小和格式与您现有的纹理相同,但具有完整的 mipmap 链。参见 newTexture 文档

使用您的 MTLCommandBuffer 对象创建 blitEncoder 对象。请参阅 blitCommandEncoder 文档

使用 blitEncoder 从您的相机纹理复制到您的空纹理。destinationLevel 应该为零,因为您只复制顶级 mipmap。请参阅 copyFromTexture 文档

最后使用 blitEncoder 通过调用 generateMipmapsForTexture 生成所有的 mip 级别。请参阅 generateMipMapsForTexture 文档

最后,您将获得来自相机的金属纹理和完整的 mip 链。

于 2014-11-10T08:18:07.860 回答