如何释放MTLBuffer和MTLTexture的内存空间

9

我知道如何创建MTLBuffer和MTLTexture,但是当这些资源不再需要时,如何释放GPU内存呢?

2个回答

17

MTLBufferMTLTexture是Objective-C对象,因此具有引用计数功能。如果您在Objective-C项目中使用自动引用计数或通过Swift使用Metal,则只需确保不再持有对缓冲区或纹理的引用,即可释放任何相关的硬件资源。

let texture: MTLTexture? = device.newTexture(with: descriptor)
texture = nil // <- resources will be released

当将nil赋值给texture时,通过逐步跟踪相关的汇编指令,可以确认这一点,该指令首先引导我们到[MTLDebugTexture dealloc].

MetalTools`-[MTLDebugTexture dealloc]:
    ...
->  0x100af569e <+34>: call   0x100af87ee               ; symbol stub for: objc_msgSendSuper2
    0x100af56a3 <+39>: add    rsp, 0x10
    0x100af56a7 <+43>: pop    rbp
    0x100af56a8 <+44>: ret    

...并通过[MTLToolsObject dealloc]

MetalTools`-[MTLToolsObject dealloc]:
    0x100ac6c7a <+0>:   push   rbp
    0x100ac6c7b <+1>:   mov    rbp, rsp
    0x100ac6c7e <+4>:   push   r14
    ...

...并通过GeForceMTLDriver实现

GeForceMTLDriver`___lldb_unnamed_symbol1095$$GeForceMTLDriver:
->  0x7fffd2e57b14 <+0>:  push   rbp
    0x7fffd2e57b15 <+1>:  mov    rbp, rsp

一路上,通过各种dealloc方法释放任何资源。


4

如果您正在使用自动引用计数(ARC),就像接受的答案所说,只需设置为nil。

但是,如果您正在使用手动引用计数(MRC),Metal有两种动态分配的资源(MTLBuffer和MTLTexture),您可以按以下方式释放它们。

id<MTLDevice> m_Device = MTLCreateSystemDefaultDevice();
// allocate Buffer
NSUInteger BufferLength = 100;
id<MTLBuffer> m_Buffer = [m_Device newBufferWithLength:BufferLength options:0]; 

// allocate Texture
MTLTextureDescriptor *shadowTextureDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: MTLPixelFormatDepth32Float width: 1024 height: 1024 mipmapped: NO];
id<MTLTexture> m_Texture = [m_Device newTextureWithDescriptor:shadowTextureDesc];

// release Buffer
[m_Buffer setPurgeableState:MTLPurgeableStateEmpty]; 
[m_Buffer release];

// release Texture
[m_Texture setPurgeableState:MTLPurgeableStateEmpty];
[m_Texture release];

关于setPurgeableState,您可以参考链接(https://developer.apple.com/documentation/metal/mtlresource/1515898-setpurgeablestate)。


我希望你能对其他MTL类型进行扩展,以使答案更好。 - Ray Garner
在我看来,只有MTLBuffer和MTLTexture需要在手动引用计数模式下释放,其他的MTL类型都是静态的。因此,当它们超出作用域时,它们会自动释放。@RayGarner - 冯剑龙
好的,那么针对使用 new 或 alloc init 分配内存的描述符呢?如果你设置了 setPurgeableState:MTLPurgeableStateEmpty,那么 release 方法调用是否百分之百必要呢? - Ray Garner
为什么仅释放不够,你还要将可清空状态设置为空?当引用计数变为0时,难道释放不会把它清空吗? - rozina
当然,你可以尝试一下。我只实现了粗暴的释放方式。 - 冯剑龙
我想补充一下,setPurgeableState:MTLPurgeableStateEmpty会导致Metal忽略缓冲区依赖关系。如果你恰好有仍在运行或计划运行的使用可清除缓冲区的内核,可能会遇到各种奇怪的行为。然而,如果你只是调用release,直到所有相关内核(确切地说是命令缓冲区)执行完毕,缓冲区才不会被释放。 - Sergei Kulik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接