在使GPUMarching多维数据集实现一段时间之前,我遇到了OpenGL保持内存的问题,我要求它发布。在Stack溢出上有很多线程,其要点似乎是您根本不能依靠API来及时释放VRAM。在我的应用程序中,我试图变得聪明,在完成网格创建后释放所有用于创建网格的临时缓冲区,并在每次网格更改时分配一个精确大小的顶点缓冲区。这适得其反,并迅速导致内存不足的崩溃.
在我的例子中,因为它只是一个uni项目的玩具应用程序,所以我通过分配最坏情况下的缓冲区来解决这个问题,并让它们分配,在网格提取过程中尽可能地为不同的通道回收缓冲区空间。这也是一种边缘情况,因为缓冲区很大(有时是数百MB),所以内存错误很快就出现了。
对于像我这样严格限制的用例来说,这很好,但是我的问题是,在游戏这样的环境中,需要动态加载和卸载大量的网格和纹理,如何处理VRAM呢?我特别想到的是像GTA这样的开放世界游戏,当玩家在游戏中移动时,这个世界不断地被传输进来,但是即使是在更线性的游戏中,加载一个新的级别也需要大量的卸载和重新加载资产。
资产是否以某种方式被加载到大型固定缓冲区和空间使用情况的区段?或者,如果使用大量的小型缓冲区,API是否能够与创建和定期销毁的几个API保持一致?任何在发动机设计方面有经验的人都能说明在实际使用中如何做到这一点吗?
发布于 2017-09-05 21:29:55
对于控制台(和D3D12/Metal/Vulkan),您知道开发分配策略所需要知道的一切。你知道:
考虑到这些信息,您可以为数据上传设计一个分配策略。开放世界的游戏使用固定大小的数据块流。游戏的每个扇区都包含占用X字节数的资源,因此,艺术家有X字节的存储空间可供使用。他们的工作就是把游戏中那个区域所需要的所有东西都放在这么大的空间里。还将为更大的区域集合提供流块,或者在所有游戏区域之间共享其他数据。
对于其他游戏,他们中的一些在水平加载时间加载所有的东西。一些在“级别”中间执行硬负载(见许多源引擎游戏)。另一些则更动态地流东西,但即使在那里,艺术家也被限制使用总计最多X字节的资源。
在控制台上,这样的大小可以事先知道,但是对于Vulkan/Metal/D3D12,必须查询它们是否有特定的硬件。因此,在后一种情况下,您必须对可用的信息做出更多的反应,但是所有的信息都是对用户可用的。
对于其他API/平台(OpenGL/D3D预-12),事情要复杂得多。控制台和低级API使您可以直接访问内存分配,这给了您更大的灵活性。您可以在某一时间点为顶点数据使用一块内存,然后稍后将图像放入其中。内存与其当前的使用不同,因此应用程序更容易选择如何回收内存。
对于GL/D3D-12前,事情是困难的。缓冲区对象是缓冲区对象,当前与其关联的内存以后不能用作纹理。当然可以,但你不能明确要求这样做。您能做的最多就是释放缓冲区,分配映像,并希望缓冲区的内存被回收。
对于在固定大小的块中动态加载的情况,基本上必须给艺术家更多的限制。与其用内存限制艺术家,还不如按对象详细说明限制,这样就可以说流块可以有“Y格式和Z大小的X纹理数,以及W字节的顶点数据”。艺术家不能牺牲4个纹理来允许一个纹理的大小是4倍,也不能牺牲一个纹理来获得更多的顶点数据,或者牺牲一些顶点数据来获得更多的纹理空间。
如果您不信任实现的内存分配程序来有效地回收资源,就必须这样做。对于硬负载情况,通常只删除所有对象并期望实现有效循环是可以的。但是,即使在这里,确保不尝试分配所有可用的存储空间也是一个好主意;将实现留给碎片等等。
当然,这类事情是IHVs进行特定应用程序优化的主要原因:它们预先知道为哪个目的分配了哪些资源,驱动程序制造者可以设计出符合这些假设的分配方案。
所以Vulkan et。al存在:这样应用程序开发人员就不必依赖于IHV来解决API中的问题。
https://computergraphics.stackexchange.com/questions/5570
复制相似问题