第四十九期 内存

 
发布日期:2020年6月12日




大家好,这里是深夜计算机节目肥猫池塘第四十九期
我是被迫在医院通关了XBDE的肥猫

最近的更新中,国服更新了韩服不久前实装的削减三觉立绘cutin的分辨率确保流畅度的优化,惨遭炎上
大部分人都觉得官方用这样的办法提高游戏的流畅度太不负责任,今天就以这个为契机,聊一下游戏里的图像显示机制

先粗略说一下电脑的内存机制是如何的
内存是电脑内极其重要的构成部分之一,它里面的内容可以高效快速地被中央处理器CPU直接调用,运行程序实际上就是计算机在处理内存里的内容
内存的读取速度是最快的,上个世纪的一些卡带游戏本质上就是断电不会消失数据的ROM内存,相对于后来光盘时代的读盘地狱,卡带的加载速度快如闪电,光碟机完全望尘莫及
但是卡带和内存一样都有一个致命的缺点,就是由于技艺原因,它们的容量都很小,上世纪末的主流电脑的内存只有128m,如果一个电脑游戏的容量超过128m,那该怎么办呢?于是和内存相对应的概念“外存”就诞生了
外存其实就是指硬盘和光碟等稳定但非核心的储存介质,外存拥有相对于内存庞大数十倍的储存空间,但是无法被cpu直接读取,电脑需要运行外存里的资料的话,就必须把它们从外存传输到可以重复读写的内存RAM里面,用不上了就将其销毁腾出空间给其他资料,通过来回重复的加载和销毁数据,使得128m内存的电脑也能够运行1g大小的游戏

dnf也是一样,这个足足18G大小的客户端正常情况下完全不会把18G的数据全部写进内存里(尽管这样做会非常高效),游戏程序只需要在必要的时刻加载必要的文件,然而这里就开始出现了问题
计算机的发展是缓慢而又快速的,32位系统要直到上世纪90年代中期才出现,在接下来的十余年内它一直都是个人电脑操作系统的主流,最早的个人用64位cpu要等到03年才出现,等到真正成为我们电脑的主流的时候已经是win7末期了(实际上由于windows那狗屎一样的兼容性,至今还没进入纯64位时代,除了苹果)
当年Inter推出的64位cpu IA64就是一个大胆的完全不兼容32位的怪胎,最后它的结果是被隔壁AMD的兼容32位的64位架构吊打,再起不能,这里可以看出我们还没有完全摆脱32位系统的影响,32位我们目前选择的态度是“尽可能地兼容”,而不是“完全放弃”
dnf.exe(32位)就是这个时代发展浪潮里面的一个“受害者”

dnf开始立项开发是17年前的2003年,那个年代刚刚好64位cpu刚刚诞生,正是32位和WinXP的极盛时代,dnf就是被深深地烙上了那个时代烙印的血统纯正的32位程序
32位系统理论上支持的寻址空间是2的32次方,也就是419430400字节=4GB的内存量,实际上因为各种各样的原因可以被识别的内存是不可能达到4G大小的,所以32位系统的程序都进行了一个“限制”,它单个进程不允许使用内存量超过2GB,因为它需要保留一定量的内存去确保操作系统的正确运行,否则会崩溃
实际上在32位系统里面还可以通过协议让单个进程的内存使用量增加到3G(理论可以完全使用到4G),但这仅仅是属于戏法而已,32位进程的极限仅仅如此,否则也不会驱使人们把目光投入到更加先进的64位系统中
现在的dnf正常情况下进入游戏后就会占据1G多的内存,仅仅是进个游戏就占用了单进程的一半内存量可以说是“开幕雷击”了,在接下来的实际游戏中游戏很快就会上涨到1.5G的内存,实际上对于一个正常的32位程序来说这已经是开始不稳定起来了,游戏这个时候开始也会进行懒释放——角色进入战斗状态时,系统会快速地加载大概200多MB的数据,这是你的角色要用到的所有技能图片,结束战斗后选择角色的话,这200多M的数据很快就被销毁了,其实这里就是在执行游戏的懒释放指令尽可能地避免游戏崩溃了,毕竟这游戏内存使用超过2G以上就很危险了



内存只是处理数据的逻辑,要真正地把处理后的结果显示到电脑屏幕上的,还需要一种叫显卡的东西
早期的显卡是集成到cpu里的,因为它本质上是处理图像信息之后传输信号到显示器上面,后来为了要处理复杂的高位数图片以及3D模型才有了独立显卡,其实内存也是差不多的进化历程
显卡里面也有和内存差不多的显示专用内存,简称显存,所有需要显示到屏幕里的内容都必须存放在显存里,原理和内存也差不多,需要用到的时候就加载,不需要用到的时候就销毁
这里有人可能就问了,既然最后都是加载到显存里,为什么图像数据不直接加载到显存里,而是要先加载到内存里,再从内存传输到显存里呢?
这是一个历史遗留问题,最早的时候还没有显存这东西,显存担当的职务由内存兼任,后来内存不够用了,就开始给显示卡划分它们专用的内存缓解燃眉之急,这造就了现代计算机的基础架构
大部分程序里面的媒体数据都是经过压缩的,要让这些压缩的数据正确地显示到屏幕里,我们需要一个名为“解码”的过程

就以dnf为例,dnf的图像文件储存的格式是img文件,多个img文件封装为压缩的npk文件存放在客户端的imagepack2文件夹中
我们操作的剑鬼进入图里战斗之后,会在进图的读条中把这个6.2mb大小的cutin_swordghost_neo.img加载到内存里,这个是剑鬼的三觉技能cutin数据

我们操纵的角色在图里使用三觉的时候,这个img就会进行软件解压,解压出几十m的可以被显卡识别的纯图像数据,这些数据被快速地传输到显存里,及时地命令显卡做出了渲染信息(还记得之前某一期里面提到过的Draw Call吗?),这就是一次完整的cpu命令gpu画画的过程
上面提到过软件解压,这是什么一回事呢?这就是属于一种比较落后的图像渲染方式了,软件解压就是指原始的压缩数据传输到内存后,通过程序本身的调配自行解压缩,因为是程序自己的活,所以解压出来的几十m可以被显卡识别的数据是直接存放在内存里的,等待被叫到的那一天
奶粉为了确保角色在图里刷图的流畅度,所以在你进图之后第一次放技能的时候会进行一次解压,然后解压后的数据直接存放在内存里,这就是一些机器第一次进图放了一次技能之后放技能不会卡顿的缘故,三觉cutin也是一样,第一次释放三觉后他们会把图像数据保留在内存里

为了使得这里的图像调用尽可能地优化,np在16年的时候进行了一次优化,上面图里面看到文件名前面有蓝色的纸张图标了吗?这意味着是Ver5 img文件,它使用dds格式存放,实际上它是DirectX纹理压缩的专用格式,拥有媲美png的压缩效率的同时可以通过黑科技大幅度地减少解码的内存占用,和上面不同的地方在于dds格式采取硬件解码的模式,它可以把原始数据直接加载到显存内部然后直接调用硬件gpu进行解码,节省了不少的内存,乃是Dx的黑科技之一,虽然dnf有没有用到这个技术还是存疑(……)

硬件解码也不是完全的黑科技,他只是相对减少了内存使用量,相反,由于机制的原因,它需要用到的时候要马上处理,所以理论上图像的处理速度反而会比上面提到的慢一些
而且需要用到内存的还是得用到的

没观察过dnf的显存使用量的朋友们可以留意下,dnf的常态显存使用量是0.3-0.4GB左右,也就是说dnf常态时候显示需要用到的显存量是380m-430m上下(估算值)
这400多mb包括了ui、角色、地图的图片等数据,这属于非常低下的水平,可以对比一下同为2d游戏的帝国时代2决定版

常驻1.3G显存占用量

以及画质效果最低的前提下,常态2.4G显存使用的鬼泣5
这两个游戏都是19年的,属于现代游戏的平均水平,和上面两个对比dnf真的是非常不吃显卡
但是在角色进行释放三次觉醒技能出现技能cutin的时候,dnf的显存使用量会猛增0.1G

这里可以看出这个三觉立绘的内存使用其实是非常可怕的,上面提到的两个游戏都是64位,这点内存使用量“湿湿碎”啦,但是对于一个32位程序来说,这就有点问题了
实际上图片的存放空间一直都是一个玄学级别的问题,它占据的空间大小会随着图片自身的画布大小呈指数级上升,而不是单纯的等比
而需要保留图片本身的半透明信息的话就“死多两钱重”,他需要使用空间更大的真彩色32位格式保存,技能cutin就是这些很典型的半透明大图的图像序列,电脑要连续处理这么多的大图是很蛋疼的
不知道各位做补丁的时候全部保存这些比较大的cutin的图片会不会感觉到明显比其他零碎的图片更慢呢?这里是使用ex对鬼剑士立绘进行部分浏览后的内存数据大小,只要用看就知道这么一大坨东西丢在内存里是多爆炸了

这还是削减分辨率后的,削减前更加林檎炸裂

一个3000*3000的气功三觉立绘png使用的硬盘空间是8.96m,而保存为800*800的32位色png图片只需要600k的大小
这还是建立在压缩的前提下,前者加载到内存里需要消耗的内存使用量是37.8m(png是一种高压图片数据)
角色动态cutin立绘平均大小是6-10m一个img,解压后大概是25m-40m一个,而一个角色进图时需要加载3个(二觉三觉和buff),单个角色光是进图加载他的觉醒立绘就需要用100m多的内存了,组队的情况下很可能光是立绘就用了500m的实际内存
削减分辨率之后平均的img大小是4-6m一个,大概的内存使用量锐减了一半达到240m左右,这个分辨率削减看似无意义,其实是一刀砍在了要害上

其实削减分辨率保证游戏的资源使用率更加协调确保游戏不崩溃其实是游戏界极其常见的做法
和大部分人想象中的不同,3D游戏里面最主要的图像耗能是贴图(Texture)的分辨率,同一个模型使用比较常见的1024*1024大小贴图和使用4096*4096的4k级贴图的耗能是相差几个时代等级的水平,一些pc上面画面很好的游戏移植到性能比较差的主机上面的话最明显的优化点就是削减贴图的分辨率,在游戏里设置动态分辨率确保流畅也是非常场景的做法,例如被人吐槽烂了的掌机模式360p古拉大草原
奶粉的cutin分辨率和谐其实也是基于上面这个原理的无奈之举,只是对于大部分观念认为“2D游戏是落后象征”的人来说这样的和谐有点不可思议,实际光就图片image的角度来说,这一点2d游戏和3d游戏其实原理完全是一样的

那么有人会吐槽,我们是玩家,他们做优化不力是他们的事情,为什么要牺牲我们的眼睛去为他们的懒惰负责呢?
先不说其他地方的优化,这个觉醒立绘cutin的庞大内存占用不是说优化一下其他东西就能解决的,所以最好的优化还是优化cutin自身,这个是大前提,那么优化这个cutin有什么办法呢?
其实目前而言就我自己研发游戏时候知道的,面对奶粉这种情况可以说出5种优化方法

1.就是业界最常见的削减分辨率大法
上面已经很详细地描述了,省略

2.完全把技能做成“演出型技能”
一些老游戏在角色放大招的时候往往会尽可能地限制彼此之间的互动,采取完全强制的方式播放技能动画
这个其实是早期压榨机能的一些妥协,例如在播放陨石术的时候,完全不渲染目前战斗的场地,把更多的资源放在渲染陨石落下的提高压迫感的特效以及处理有限的互动中
如果觉得抽象的话,就在奶粉中举个例子吧,最典型例子就是把三觉技能做成完全的动画,目前的三觉技能为了保持互动,其实是采取了正常技能的制作手段的
完全动画化的三觉技能就是加载一个高压高清avi文件进行播放,包括三觉动态cutin,完全舍弃和怪物的互动,播放完毕之后结算伤害
当然这样就完全践踏了dnf标榜的“行动快感”了,所以这种手段是不会考虑的

3.半播片流
这个是和上面原理差不多,把三觉cutin做成avi的形式,avi是目前最成熟的视频格式,很多黑科技让他们可以高效地调用
但是avi完全不支持透明通道,在win里面的原生avi都不会有透明的,但是我们不需要强求avi透明,我们只需要用蒙板模拟透明就ok了
作为三觉立绘的母体avi是正常的高清压缩视频,然后调用另一个保留了黑白色蒙板信息的avi对母体进行蒙板遮罩,保留只需要保留的信息,扣掉需要透明的底部


这样就可以使用avi模拟现在的png序列效果,理论上这样是更加高效的,但是缺点也很明显:时间轴非常难对得上,而且对程序员对文件结构的理解需求比较大(最难就是如何真的在游戏里做出来)
而且使用蒙板的效率是否比现在的要高还得存疑

4.人肉Live2d
一些市面上的游戏也用到了类似dnf的全屏cutin演出效果,例如之前作为范本被拉出来战撸的手游第七史诗
但是不要以为他们这种演出的原理是和奶粉差不多的,奶粉这种做法是极其消耗资源的,在手机上的贫乏环境下要照搬过来是不可能的
实际上第七史诗里面的动画的帧率比奶粉少一半以上,而且他们的战斗系统的即时互动性不高,同屏actor也很少,所以他们有足够的资源把这种演出做出来
而且有部分帧是用了“伪·live2d”的模式进行部件移动对动画本身进行补间,让动画以最少的占用获得最流畅的演出

例如这个演出里面角色前半段的动作活动帧只有6帧,后半段可以用差分+补间动画的技术模拟出来,不用数十帧序列帧的模式制作出来
缺点就是过于死板,而且对动画程序的工作量要求很大,不是闲着蛋疼不会这样搞
而且动画过于复杂的话其实优化的空间微乎其微
事实上开发方也意识到帧数太高得到的效果不理想,所以女格斗三觉他们cutin的帧数明显下调进行优化了,例如最少的是柔道家的10帧,相比于红眼的40多帧更加环保

5.完全不做
这个就是最好的办法,他们这种大屏幕序列动画演出本身就是极其不环保的行为
如果是我做游戏的话,我肯定不会用这种演出
完全不做的话最后就不只是炎上那么简单了,所以看了这么多方法,还是1最简单暴力,可能还是唯一解
总结就是之所以这样做并不是什么懒惰,而是确实地遇到了技术壁垒了

以上就是针对这次分辨率河蟹事件的一些杂谈了,下面就提一下一些大家在辱骂官方时候容易陷入的误区吧
奶粉这个游戏因为是市面上几乎死绝的2D游戏所以用主流看法看它产生的误解一直很多
首先就是最经典的误解:dnf的客户端里面有很多过期没用的活动贴图,官方宁愿河蟹分辨率都不删除他们进行优化
这个其实阅读上面的内容之后就会明白,这些过期的贴图压根就不会加载到内存里,永远都不会为你的游戏崩溃负任何责任
之所以不删除的原因是因为pvf会极其容易丢失路径造成游戏莫名其妙的崩溃
现在硬盘那么大,冒着游戏bug的危险清理一些空间出来的做法本身就没什么意义

底层代码如同意大利面,赚这么多钱都不懂得优化一下
能够运营十几年的游戏没有一个不是意大利面代码,而且奶粉程序员的描述已经很文雅了,隔壁wow直接用屎山来辱骂自家的代码
那不是优化不优化的问题,是压根没什么优化的余地

一核有难多核围观,dnf还是一个落后的单核游戏
市面上99.9%的游戏都是一核有难多核围观的,多核游戏压根不是np这种技术主导小厂商可以玩得起的
举个例子,多核优化不是让你四个人去分摊写四本书,而是让你四个人分摊写同一本四倍普通书厚度的书里面的内容,市面上很多所谓的多核优化其实也只是把原先一个核可以处理完的东西分到几个核上面减轻一下压力而已

赚了这么多钱,都能够把游戏重做十几次了
NS版的勇者斗恶龙11发售时间比ps4版的晚了两年,原因是ns的移植难度太高,光是移植同一个游戏都可以花费两年的时间了,不是有这个游戏就能很轻松地重做出来的
运营了十几年的网游体量无比庞大,而且程序员频繁交替,把游戏重做出来,就算只还原原来游戏八成感觉也非常困难
况且重做之后不代表一定比不重做要好,现在的客户端很多东西都是经历了风风雨雨之后得到的最优解,新人完全不会理解为什么老客户端要这样搞
有人说直接把dnf升级到64位程序不就行了,这个的确,有些32位程序甚至可以直接一个编译器就能解决的事情
但是这只是理论上的情况而已,对于大型网络游戏来说编写的时候没有一些邪魔外道完全是不可能的,光是C++的整数型如果直接使用元祖类型的话都会根据32位和64位系统决定容量,类似的情况还有很多,依附于平台的特征选择写法去编写源码是很正常的情况,但这些方便很可能会成为换代时期的隐形炸弹,给你的美好蓝图涂上一层层恶心的呕吐物,如果真的问题不大的话他们是不可能不升级的,更悲观一点花上四五年时间才写得出来也不是什么奇怪的情况

dnf只是一个2d横版贴图格斗游戏,连xxx(3d游戏)都可以流畅运行,他竟然可以闪退
1.dnf的分类是属于MORPG(注意不是MMORPG)类下的벨트스크롤 액션게임(Belt Scroll Action Game,清版过关动作游戏),为什么把dnf称作格斗游戏,和tx的错误宣传有关,现在这个词还挂在每次更新时候的公告的最下面,事实上可以把僵直和硬直两个词同时放到同一个游戏里的压根就不懂什么是格斗游戏
2.2d游戏就不见得是落后的象征,现在2d游戏引擎还有一定的市场,不是因为2d游戏制作难度低,而是2d游戏的图像思路和3d游戏的思路完全是两个次元的,如果见识过用3d环境模拟2d游戏产生的tile缝隙的话对这个观点会有更加深入的了解,实在是蛋疼不已。dnf也就图形方面完全不需要显卡的计算能力而已,其他地方其实和现在的游戏没什么区别。早期的dnf是参考了fps的网络同步模式做的act网游同步模式,计算量很大,问题多多
3.dnf可不是什么贴图(texture)游戏,计算机画面的最基本单位是图像(Image),贴图是专门指通过uv关系映射到三维模型上的图像,好像贴纸一样贴在模型上,所以才得名贴图。贴图所担当的也不是单纯的图像信息,里面的一些信息也可以给模型产生特殊计算产生不同的效果,例如扭曲光线的角度产生凹凸感的法线贴图等,任何一个主流的3D游戏都比奶粉有资格称为“贴图游戏”。奶粉其实更适合称之为“精灵游戏”,精灵(Sprite),又叫雪碧,是指游戏引擎里对一张sheet图或者多张零散的小图进行封装打包后的单位,他作为单位之后可以被引擎视为个体进行互动,不仅是2d游戏,3d游戏里面一些物件也是精灵,dnf自己的文件名就是这样命名的


最后还是感叹一句吧,目前dnf遇到的问题其实反映了2d游戏衰落的大环境
实际上很多3d游戏画面按照正常做法来做的话是完全不够机能做出来的,但是3d游戏制作环境不仅是硬件进化的速度日新月异,而且因为是目前主流的类型所以欺诈玩家眼球降低资源消耗的戏法(Trick)越来越多,反之2D游戏的戏法其实十几年来是完全停滞的,大概这种类型的游戏发展已经到达了巅峰,已经不需要任何的进步了吧
有些东西无法勉强,只能在妥协中做到最好而已,这大概也是属于他们的无可奈何吧
小道消息:他们会在不久之后就解决这个cutin问题,抱着平常心期待一下吧

行动快感!地牢与战斗机
 

回到目录