Reputation: 3614
Xcode's GPU frame capture
highlight multiple expressions as purple and say I should set the texture storage mode to private
because only GPU access it. I am trying to fix the purple suggestion.
Memory Usage'Texture:0x10499ae00 "CoreVideo 0x6000017f2bc0"' has storage mode 'Managed' but is accessed exclusively by a GPU
When using device.makeBuffer(bytes:length:options:)
to create MTLTexture
, I can set storageMode
to private
in the argument options
.
But when create MTLTexture
from CVPixelBuffer
through CVMetalTextureCacheCreateTextureFromImage()
, I don't know how to configure the storage mode for the created texture.
Ways I tried:
textureAttributes
argument in CVMetalTextureCacheCreateTextureFromImage(..., _ textureAttributes: CFDictionary?, ...)
var textureAttrs: [String: Any] = [:]
if #available(macOS 10.15, *) {
textureAttrs[kCVMetalTextureStorageMode as String] = MTLStorageMode.private
}
CVMetalTextureCacheCreateTextureFromImage(,,,textureAttrs as CFDictionary,..., &texture)
if let texture = texture,
let metalTexture = CVMetalTextureGetTexture(texture) {
print(metalTexture.storageMode.rawValue)
}
}
My OS is already 10.15.4, but the created MTLTexture
still has storageMode
as managed/rawValue: 1
CVMetalTextureCacheCreate()
which creates the cache for CVMetalTextureCacheCreateTextureFromImage
in cacheAttributes
and textureAttributes
.The result is the same.
Problems:
References:
Upvotes: 4
Views: 1152
Reputation: 999
To set the texture attributes - you muse use the rawValue
of the MTLStorageMode
. For example:
var textureAttrs: [String: Any] = [:]
if #available(macOS 10.15, *) {
result[kCVMetalTextureStorageMode as String] = MTLStorageMode.managed.rawValue
}
var textureCache: CVMetalTextureCache!
let textureCache = CVMetalTextureCacheCreate(
nil, nil, device, textureAttrs as CFDictionary, &self.textureCache)
Once the cache is created with those texture attributes, you can pass nil as the texture attributes in CVMetalTextureCacheCreateTextureFromImage
when creating each texture as it will use whatever storage mode the cache was created with. For example:
var cvTexture: CVMetalTexture?
CVMetalTextureCacheCreateTextureFromImage(nil, textureCache, pixelBuffer, nil, .bgra8Unorm, width, height, 0, &cvTexture)
Something to note - I was getting metal warnings in Xcode that my textures should be made private instead of managed, but when setting the cache to a private storage mode, the following error occurred:
failed assertion 'Texture Descriptor Validation IOSurface textures must use MTLStorageModeManaged'
This is because these textures are IOSurface-backed. So for now I'm keeping it managed.
Upvotes: 0
Reputation: 454
I have experience with Metal and had the same kind of issue. There is no way to change texture storageMode
one the fly. You have to create another MTLTexture
with desired storageMode
and use MTLBlitCommandEncoder
to copy data to it.
Here is the piece of code from my project:
MTLTextureDescriptor* descriptor = [[MTLTextureDescriptor alloc] init];
descriptor.storageMode = MTLStorageModePrivate;
descriptor.pixelFormat = MTLPixelFormatRGBA8Unorm;
descriptor.width = width;
descriptor.height = height;
id<MTLTexture> texture = [__metal_device newTextureWithDescriptor: descriptor];
if ((data != NULL) && (size > 0)) {
id<MTLCommandQueue> command_queue = [__metal_device newCommandQueue];
id<MTLCommandBuffer> command_buffer = [command_queue commandBuffer];
id<MTLBlitCommandEncoder> command_encoder = [command_buffer blitCommandEncoder];
id<MTLBuffer> buffer = [__metal_device newBufferWithBytes: data
length: size
options: MTLResourceStorageModeShared];
[command_encoder copyFromBuffer: buffer
sourceOffset: 0
sourceBytesPerRow: (width * 4)
sourceBytesPerImage: (width * height * 4)
sourceSize: (MTLSize){ width, height, 1 }
toTexture: texture
destinationSlice: 0
destinationLevel: 0
destinationOrigin: (MTLOrigin){ 0, 0, 0 }];
[command_encoder endEncoding];
[command_buffer commit];
[command_buffer waitUntilCompleted];
}
Upvotes: 0