OSX MetalKit CVMetalTextureCacheCreateTextureFromImage 失败,状态:-6660
OSX MetalKit CVMetalTextureCacheCreateTextureFromImage failed, status: -6660
我首先尝试从 RAW 内存中制作 CVPixelBuffer
然后 MTLTexture
来自 CVPixelBuffer
,但是
在 运行 以下代码之后我总是遇到错误
CVMetalTextureCacheCreateTextureFromImage failed, status: -6660 0x0
这个错误是从哪里来的?
id<MTLTexture> makeTextureWithBytes(id<MTLDevice> mtl_device,
int width,
int height,
void *baseAddress, int bytesPerRow)
{
CVMetalTextureCacheRef textureCache = NULL;
CVReturn status = CVMetalTextureCacheCreate(kCFAllocatorDefault, nullptr, mtl_device, nullptr, &textureCache);
if(status != kCVReturnSuccess || textureCache == NULL)
{
return nullptr;
}
NSDictionary* cvBufferProperties = @{
(__bridge NSString*)kCVPixelBufferOpenGLCompatibilityKey : @YES,
(__bridge NSString*)kCVPixelBufferMetalCompatibilityKey : @YES,
};
CVPixelBufferRef pxbuffer = NULL;
status = CVPixelBufferCreateWithBytes(kCFAllocatorDefault,
width,
height,
kCVPixelFormatType_32BGRA,
baseAddress,
bytesPerRow,
releaseCallback,
NULL/*releaseRefCon*/,
(__bridge CFDictionaryRef)cvBufferProperties,
&pxbuffer);
if(status != kCVReturnSuccess || pxbuffer == NULL)
{
return nullptr;
}
CVMetalTextureRef cvTexture = NULL;
status = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
textureCache,
pxbuffer,
nullptr,
MTLPixelFormatBGRA8Unorm,
1920,
1080,
0,
&cvTexture);
if(status != kCVReturnSuccess || cvTexture == NULL)
{
std::cout << "CVMetalTextureCacheCreateTextureFromImage failed, status: " << status << " " << cvTexture << std::endl;
return nullptr;
}
id<MTLTexture> metalTexture = CVMetalTextureGetTexture(cvTexture);
CFRelease(cvTexture);
return metalTexture;
}
当 CVPixelBuffer 不受 IOSurface 支持时会发生错误。但是,您不能从字节创建 IOSurface 支持的 CVPixelBuffer。因此,尽管设置了 kCVPixelBufferMetalCompatibilityKey
,CVPixelBufferCreateWithBytes
(及其平面对应物)不会使用 IOSurface 支持缓冲区。
2 种解决方法(可能还有第 3 种)
- 创建一个空的 CVpixelBuffer 并使用 memcpy。您需要在每个循环中创建一个新的像素缓冲区,因此建议使用 PixelBufferPool。
CVPixelBufferPoolRef pixelPool; // initialised prior
void *srcBaseAddress; // initialised prior
CVPixelBufferRef currentFrame;
CVPixelBufferPoolCreatePixelBuffer(nil, pixelPool, ¤tFrame);
CVPixelBufferLockBaseAddress(currentFrame,0);
void *cvBaseAddress=CVPixelBufferGetBaseAddress(currentFrame);
size_t size= CVPixelBufferGetDataSize(currentFrame);
memcpy(cvBaseAddress,srcBaseAddress,size);
- 完全跳过CVPixelBuffer,直接写入MTLTexture内存;只要金属支持你的像素格式。但是,由于您可能正在渲染到 RGB 显示器,因此您可以编写自己的金属内核以转换为 RGB。记得先用metalTextureDescriptor制作贴图。
id<MTLDevice> metalDevice; // You know how to get this
unsigned int width; // from your source image data
unsigned int height;// from your source image data
unsigned int rowBytes; // from your source image data
MTLTextureDescriptor *mtd = [MTLTextureDescriptor
texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRG422
width:width
height:height
mipmapped:NO];
id<MTLTexture> mtlTexture = [metalDevice newTextureWithDescriptor:mtd];
[mtlTexture replaceRegion:MTLRegionMake2D(0,0,width,height)
mipmapLevel:0
withBytes:srcBaseAddress
bytesPerRow:rowBytes];
第三种方法可能是将 CVPixelBuffer 转换为 CIImage,并使用 Metal 支持的 CIContext。像这样;
id<MTLDevice> metalDevice;
CIContext* ciContext = [CIContext contextWithMTLDevice:metalDevice
options:[NSDictionary dictionaryWithObjectsAndKeys:@(NO),kCIContextUseSoftwareRenderer,nil]
];
CIImage *inputImage = [[CIImage alloc] initWithCVPixelBuffer:currentFrame];
[ciContext render:inputImage
toMTLTexture:metalTexture
commandBuffer:metalCommandBuffer
bounds:viewRect
colorSpace:colorSpace];
我成功地使用它直接渲染到 CAMetalLayer 的可绘制纹理,但渲染到中间纹理时运气不佳(并不是说我非常努力地让它工作)希望其中一个对你有用。
我首先尝试从 RAW 内存中制作 CVPixelBuffer
然后 MTLTexture
来自 CVPixelBuffer
,但是
在 运行 以下代码之后我总是遇到错误
CVMetalTextureCacheCreateTextureFromImage failed, status: -6660 0x0
这个错误是从哪里来的?
id<MTLTexture> makeTextureWithBytes(id<MTLDevice> mtl_device,
int width,
int height,
void *baseAddress, int bytesPerRow)
{
CVMetalTextureCacheRef textureCache = NULL;
CVReturn status = CVMetalTextureCacheCreate(kCFAllocatorDefault, nullptr, mtl_device, nullptr, &textureCache);
if(status != kCVReturnSuccess || textureCache == NULL)
{
return nullptr;
}
NSDictionary* cvBufferProperties = @{
(__bridge NSString*)kCVPixelBufferOpenGLCompatibilityKey : @YES,
(__bridge NSString*)kCVPixelBufferMetalCompatibilityKey : @YES,
};
CVPixelBufferRef pxbuffer = NULL;
status = CVPixelBufferCreateWithBytes(kCFAllocatorDefault,
width,
height,
kCVPixelFormatType_32BGRA,
baseAddress,
bytesPerRow,
releaseCallback,
NULL/*releaseRefCon*/,
(__bridge CFDictionaryRef)cvBufferProperties,
&pxbuffer);
if(status != kCVReturnSuccess || pxbuffer == NULL)
{
return nullptr;
}
CVMetalTextureRef cvTexture = NULL;
status = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
textureCache,
pxbuffer,
nullptr,
MTLPixelFormatBGRA8Unorm,
1920,
1080,
0,
&cvTexture);
if(status != kCVReturnSuccess || cvTexture == NULL)
{
std::cout << "CVMetalTextureCacheCreateTextureFromImage failed, status: " << status << " " << cvTexture << std::endl;
return nullptr;
}
id<MTLTexture> metalTexture = CVMetalTextureGetTexture(cvTexture);
CFRelease(cvTexture);
return metalTexture;
}
当 CVPixelBuffer 不受 IOSurface 支持时会发生错误。但是,您不能从字节创建 IOSurface 支持的 CVPixelBuffer。因此,尽管设置了 kCVPixelBufferMetalCompatibilityKey
,CVPixelBufferCreateWithBytes
(及其平面对应物)不会使用 IOSurface 支持缓冲区。
2 种解决方法(可能还有第 3 种)
- 创建一个空的 CVpixelBuffer 并使用 memcpy。您需要在每个循环中创建一个新的像素缓冲区,因此建议使用 PixelBufferPool。
CVPixelBufferPoolRef pixelPool; // initialised prior
void *srcBaseAddress; // initialised prior
CVPixelBufferRef currentFrame;
CVPixelBufferPoolCreatePixelBuffer(nil, pixelPool, ¤tFrame);
CVPixelBufferLockBaseAddress(currentFrame,0);
void *cvBaseAddress=CVPixelBufferGetBaseAddress(currentFrame);
size_t size= CVPixelBufferGetDataSize(currentFrame);
memcpy(cvBaseAddress,srcBaseAddress,size);
- 完全跳过CVPixelBuffer,直接写入MTLTexture内存;只要金属支持你的像素格式。但是,由于您可能正在渲染到 RGB 显示器,因此您可以编写自己的金属内核以转换为 RGB。记得先用metalTextureDescriptor制作贴图。
id<MTLDevice> metalDevice; // You know how to get this
unsigned int width; // from your source image data
unsigned int height;// from your source image data
unsigned int rowBytes; // from your source image data
MTLTextureDescriptor *mtd = [MTLTextureDescriptor
texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRG422
width:width
height:height
mipmapped:NO];
id<MTLTexture> mtlTexture = [metalDevice newTextureWithDescriptor:mtd];
[mtlTexture replaceRegion:MTLRegionMake2D(0,0,width,height)
mipmapLevel:0
withBytes:srcBaseAddress
bytesPerRow:rowBytes];
第三种方法可能是将 CVPixelBuffer 转换为 CIImage,并使用 Metal 支持的 CIContext。像这样;
id<MTLDevice> metalDevice;
CIContext* ciContext = [CIContext contextWithMTLDevice:metalDevice
options:[NSDictionary dictionaryWithObjectsAndKeys:@(NO),kCIContextUseSoftwareRenderer,nil]
];
CIImage *inputImage = [[CIImage alloc] initWithCVPixelBuffer:currentFrame];
[ciContext render:inputImage
toMTLTexture:metalTexture
commandBuffer:metalCommandBuffer
bounds:viewRect
colorSpace:colorSpace];
我成功地使用它直接渲染到 CAMetalLayer 的可绘制纹理,但渲染到中间纹理时运气不佳(并不是说我非常努力地让它工作)希望其中一个对你有用。