我有一个质量很重的OpenGL游戏,我想根据设备有多少RAM进行调整。最高分辨率的纹理我在iPhone 4或iPad2上运行良好,但早期的设备在加载纹理的过程中崩溃。我有这些纹理的低分辨率版本,但我需要知道何时使用它们。
我目前的策略是检测特定的旧设备(3GS具有低分辨率屏幕; iPad没有摄像头),然后只加载IPad2及以上和iPhone 4及以上的高分辨率纹理 - 我想我我需要为iPod touch做点什么。但我更倾向于使用特征检测而不是硬编码设备模型,因为模型检测对于API和硬件的未来变化是脆弱的。
我正在考虑的另一种可能性是首先加载高分辨率纹理,然后在我得到低内存警告时丢弃并用lo-res替换它们。但是,我不确定我是否有机会回应;我注意到应用程序经常在调试控制台上出现任何通知之前就已经死了。
如何检测我正在运行的设备是否有足够的RAM来加载我的纹理的高分辨率版本?
退一步,是否有一些其他自适应技术可以用于OpenGL纹理内存?
注意:
我搜索和关闭SO以获得与可用RAM检测相关的答案,但他们基本上都建议分析内存使用情况并消除浪费(最大限度地减少临时工作的生命周期,以及所有那些guff)。我已经做了尽可能多的事情,并且我无法将高分辨率纹理压缩到旧设备中。
PVRTC不是一种选择。纹理包含片段着色器要使用的数据,并且必须以无损格式存储。
答案 0 :(得分:11)
要获取设备的总(最大)物理RAM,请使用[NSProcessInfo processInfo].physicalMemory
。
请参阅Documentation。
答案 1 :(得分:7)
总体物理RAM可通过sysctl()
获取,如this blog post中所述,并作为一个干净的API here实现(请参阅相应.m中totalMemory
的实现)文件)。
为了方便和后人,我提起了博客的代码:
#include <sys/sysctl.h>
size_t phys_mem()
{
int mib[] = { CTL_HW, HW_PHYSMEM };
size_t mem;
size_t len = sizeof(mem);
sysctl(mib, 2, &mem, &len, NULL, 0);
return mem;
}
我不知道Apple是否会批准以这种方式使用sysctl()
的应用。它已记录在案,但仅适用于Mac OS X.
答案 2 :(得分:2)
在这种情况下,您最需要了解的内存管理是使用高分辨率或低分辨率纹理。我使用的最简单的方法是检查这个
CGFloat scale = [[UIScreen mainScreen] scale];
if ((scale > 1.0) || (self.view.frame.size.width > 320)) {
highRes = TRUE;
}
这适用于所有设备到目前为止,应该是未来的证据,较新的设备将使用高分辨率。 你也可以在那里计算宽高比(稍后在ipad和iphone上帮助)
aspect = self.view.frame.size.width/self.view.frame.size.width
首先不要加载highres它会导致你的应用程序加载时间,在我的3G上我的大多数启动都花在加载(甚至是低分辨率)纹理上,只是在开始时测试这个并且不要触摸高端的东西
在较旧的设备上,由于纹理较大,程序会在没有警告的情况下死亡,这可能与调试器无法捕获视频内存消耗和自身死亡有关。
要获得更好的优化,请考虑使用mipmap来检查实际使用的最低纹理大小(仅当您使用3D对象时)。
忘记视频RAM大小问题,内存实际上是共享的,所以你在竞争系统内存,在旧设备上你有MB限制使用,但它仍然是系统内存。
关于内存管理,有很多方法可以做到,最简单的应该是标记加载的纹理,以及需要的纹理,当内存警告到来时,转储已加载但不需要的纹理......
答案 3 :(得分:0)
据我所知,最重要的三件事是 -
- (void)didReceiveMemoryWarning
并在iOS发出警告时响应1&amp; 2。我认为你正在做大部分工作。事情是,人们甚至不知道iOS设备有多少内存。 Apple不会发布iOS设备的技术规格。
此外,不能假设只有在消耗100mb之后才会收到mem警告。 iOS提供的警告因设备的当前状态而异。正在运行的其他应用程序&amp;他们消耗了多少内存。所以它变得棘手。
我可以建议2必读部分 - Best Practices for Working with Texture Data和Tuning Your OpenGL ES Application