当使用可清除状态为volatile的纹理时,我的应用程序会崩溃并出现以下错误:"MTLDebugCommandBuffer lockPurgeableObjects]:2103:断言失败"MTLResource在提交时处于易失性或空可清除状态";
当我自己运行应用程序时(不使用Xcode中的播放按钮,只点击构建图标(,它运行得非常好,在iOS上测试时也能运行。这是最近的一个问题,因为最近更新到了Xcode的新版本。这是我可以关闭的东西吗,这样命令缓冲区就不会锁定可清除的对象?
它按预期工作。让我解释一下。
首先,你在应用程序中没有看到这个问题是因为默认情况下,从Xcode启动的应用程序使用金属验证层运行。这是一个API层,位于实际的API和您的应用程序之间,并验证所有对象是否处于一致状态,是否满足所有要求的先决条件等。在Xcode之外运行的应用程序默认情况下没有启用该层,因为进行所有验证都有其成本,你不想将其传递给用户,因为金属验证层的存在是为了在开发过程中使用。您可以通过在终端中键入man MetalValidation
来了解更多信息。您还可以在不使用Xcode的情况下启用验证的情况下运行应用程序,方法是使用MTL_DEBUG_LAYER=1
从终端进行调用。
事实上,该应用程序实际上并没有崩溃,而且在没有验证层的情况下似乎可以正常工作,这并不一定意味着它会在任何情况下和每个平台上工作。有些司机可能更严格,有些则不那么严格。这就是验证层存在的原因。
其次,让我们解决实际问题。存在可清除状态,这样Metal就可以在系统内存压力过高时选择丢弃一些资源,而不是对应用程序进行喷射。只有那些被标记为volatile
的资源才能以这种方式被丢弃。但你不能只是";设置它并忘记它";。它旨在用于非常大且可以安全丢弃的非经常使用的资源。在这个WWDC视频中描述了一般模式,大约从39分钟开始。基本上,如果你要使用一个易失性资源,你需要确保它没有被丢弃,也要使它成为非易失性的。您需要使用nonVolatile
状态显式调用setPurgeableState
,并检查它是否返回empty
(setPurgeableState
返回资源在调用前的状态(。如果是,则资源被丢弃,您需要重新生成或重新加载资源。如果没有,那么资源仍然存在。例如,您可以在命令缓冲区中安全地使用它,然后在完成处理程序中将它设置回volatile
。
我建议看这部分视频,因为它更深入。
此外,请参阅一篇文章《减少金属应用程序的内存占用》,WWDC视频调试Metal中的GPU端错误和setPurgableState
的文档页面