与大多数其他软件相比,MMO游戏客户端都是GPU开销大户,而玩家多开客户端是非常常见的行为。伴随着多开,内存开销和GPU显存开销都会成倍增加。对于大多数配置不是太高的电脑(包括笔记本)来说,显存压力过大,显卡驱动就会频繁的将部分显存交换到内存中,进而带来游戏特别卡顿、风扇狂转、机箱发热,甚至游戏崩溃等情况,严重的影响了玩家的游玩体验。实际上,同一个游戏客户端,在玩家多次启动登录进入游戏时,不少资源是可以共享的。本文将介绍新倩女幽魂如何共享显存方面的工作。
新倩女幽魂是一款pc端游,是雷火的第一款成功游戏,也是雷火运营最长的游戏,到2021年4月份已经成功运营10年。从制作初期,就设定为允许玩家多开。我们在2020年下半年,对倩女完成了次世代引擎的迭代升级,将游戏画面效果提升到了一个新的高度。不过更好的效果,必然会用到更大的资源量,如何在效果好的同时,又能尽可能降低开销,提高性能,一直是工作的一个重点。当经过很长一段时间的性能挖掘后,我们认为在当前架构下该做的都做了。但一直有一个声音在耳边回响:“我们还能优化吗?“
共享是一个很好的思路,我们前期做了内存方面的共享,收获到很好的效果,由此可以想象,如果显存也能做共享,那无疑可以给大量硬件不是太高的玩家多开时降低其开销,优化性能。
玩过梦幻西游的同学知道,梦幻有一个“中心服务”进程,似乎是做什么共享的。 梦幻是网易一款非常成功而古老的游戏,它是一款2D游戏,基于dx9和32位系统。出于对其“中心服务”进程的好奇,对它做了一番调研。
梦幻的做法是,当游戏客户端启动,会额外启一个“中心服务”进程(即便把它kill掉,它也会自启动),把各客户端换装系统里需要展示的3D模型,渲染成2D贴图,之后通过内存共享的方式,同步给客户端用于展示,解决了换装贴图组合爆炸的问题。其架构大致如下图展示:
上述梦幻西游的共享方案,有以下几个问题:
由此可知,梦幻的方案并不适合我们。
了解到DX11下有一个函数:OpenSharedResource(https://docs.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-id3d11device-opensharedresource),这个函数的功能是可以做显存资源共享。我在游戏中做了如下的测试:
1. 在一个客户端将某张贴图创建好后,在另一个客户端通过OpensharedResource获取,是可以成功使用的,不过看不出来对性能有什么提高。
2. 进一步测试,将一个客户端下所有贴图都创建成可共享的,另一个客户端通过共享的方式去打开,游戏本身没问题,但通过对比测试可得知,游戏占用的GPU开销,与不共享的客户端多开对比,并没有明显降低。
由此猜测,OpenSharedResource在多个进程之间共享显存,在显卡驱动底层,应该是拷贝了多份,避免出问题。所以只是调用这个函数来共享资源,也达不到我们要的节省显存之目的。
3. 最后又做了另一个测试:将一个客户端渲染的结果RT,通过共享给另一个客户端输出,成功。
所以,如果要真正达到降低显存的目的,得要把游戏的架构调整一下,即:创建一个“中心渲染”进程,把所有的资源和渲染指令都交给它负责,每个客户端拿到一个渲染结果的RT,输出到各自客户端下。这个思想有点像云游戏的思路,所不同的是,本地启动的“中心渲染”进程提供了云渲染服务,相当于本地云游戏。
中心渲染的核心思路,主要有以下几点:
即:每个客户端当前想要做渲染,中心渲染能立即处理渲染指令,并快速返回渲染结果到对应客户端。为了做到这一点,将原来直接对DX API的调用操作抽象了一层;引入内存共享,在中心渲染与客户端之间,共享同一块内存,在这块内存中,通过不加锁的Ringbuffer(环形缓冲区)发送客户端渲染的DX API命令。中心渲染进程会开启多个线程,每个线程处理一个客户端的RenderCommand(渲染指令),并通过DeferredContext将命令汇总起来,在一帧渲染结束时,执行FinishCommandlist把命令打包,最终在中心渲染的主线程做ImmediateContext的ExecuteCommandlist,渲染结果拷贝回各自客户端所指定的RT。同时需要处理多个客户端之间数据的隔离,不能出现多个客户端之间串流数据的情况。
对于创建资源的操作,比如创建贴图,通过把贴图路径计算hash值,在中心渲染进程,可以查表获取该hash的资源是否已经创建,如果已经创建,则无需重复创建,直接将其引用计数+1并返回结果即可。同理对于shader、mesh等数据也做一样的处理,如此多个客户端同一份资源,在中心渲染进程中,只有一份。
整个中心渲染的架构,大致如下图所示
具体技术细节,参照图中标注,依次为:
1. 游戏客户端所需要调用的所有DX API都将经过Center DX API层进行调用,该层会将相关的调用进行封装,将数据放在合适的位置,发送给中心渲染进程。
2. 基于共享内存技术,在游戏客户端与中心渲染进程之间,同享了一份内存,依赖该内存将客户端渲染相关API指令发送到中心渲染进程。其中API命令本身储存在Ringbuffer中,实现无锁访问;这种架构下,中心渲染读取渲染指令速度非常快,与在本客户端直接渲染的效率基本一致,无延时。
3. 中心渲染下的多线程架构,每个线程创建DeferredContext处理各个客户端发过来的指令,客户端之间的渲染互不干扰,在每帧结束时,会执行FinishCommandList,提交到主线程执行ExecuteCommandList实现真正的渲染。
4. 把渲染结果,通过CopyResource拷贝回一份“共享的贴图”,此贴图是通过每个客户端自己调用CreateTexture2D创建RT,但其MiscFlags设置为D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX,在中心渲染的Device上,通过OpenSharedResource做成跨Device设备的资源。直接在显卡GPU底层达到共享。最后每个客户端把这张RT呈现在自己的屏幕窗口上。
5. 多个中心渲染的线程之间,实现GPU资源的共享,当每个客户端发过来的指令是创建资源(比如创建贴图),则算出对应贴图路径的hash值(通常是一个64位整数),根据这个hash查找对应全局表(或者在全局表中创建对应资源)。每份资源只允许创建一次,重复创建情况下只是引用计数的增加。
当中心渲染架构已基本完成后,本地三开,任务管理器里看到的性能截图:
从上图可见,中心渲染架构后,游戏 本身客户端所占GPU开销已经很低很低,都集中在中心渲染进程。
经过自动化压力测试(测试机:Win10,i7-7700, 16G, 机械硬盘, GTX1060),关键性能对比数据如下:
1. fps (6开多人压测)
2. 总GPU占用(3开)
3. 专用内存集(3开)
从测试结果可知,启用了中心渲染架构后的客户端,在fps基本不变的情况下,总的显存占用有所下降(如果是可共享的资源更多,则会更省,比如在同一个场景下),符合我们的预期。
新倩女幽魂作为一款老游戏,如何在原有游戏内容上推陈出新,性能上不断迭代和优化,是我们开发人员要一直思考的问题。从近期很火的云游戏的概念中获得启发,我们实现了客户端中心渲染的架构,对于客户端多开有了一定的提升。另外一个好处是,由于资源的集中管理,我们对于查一些资源泄漏等问题,更方便了。
原网址: 访问
创建于: 2021-10-22 16:52:18
目录: default
标签: 无
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
java windows火焰图_mob64ca12ec8020的技术博客_51CTO博客 - 在windows下不可行,不知道作者是怎样搞的 监听SpringBoot 服务启动成功事件并打印信息_监听springboot启动完毕-CSDN博客 SpringBoot中就绪探针和存活探针_management.endpoint.health.probes.enabled-CSDN博客 u2u转换板 - 嘉立创EDA开源硬件平台 Spring Boot 项目的轻量级 HTTP 客户端 retrofit 框架,快来试试它!_Java精选-CSDN博客 手把手教你打造一套最牛的知识笔记管理系统! - 知乎 - 想法有重合-理论可参考 安宇雨 闲鱼 机械键盘 客制化 开贴记录 文本 linux 使用find命令查找包含某字符串的文件_beijihukk的博客-CSDN博客_find 查找字符串 ---- mac 也适用 安宇雨 打字音 记录集合 B站 bilibili 自行搭建 开坑 真正的客制化 安宇雨 黑苹果开坑 查找工具包maven pom 引用地 工具网站 Dantelis 介绍的玩轴入坑攻略 --- 关于轴的一些说法 --- 非官方 ---- 心得而已 --- 长期开坑更新 [本人问题][新开坑位]关于自动化测试的工具与平台应用 机械键盘 开团 网站记录 -- 能做一个收集的程序就好了 不过现在没时间 -- 信息大多是在群里发的 - 你要让垃圾佬 都去一个地方看难度也是很大的 精神支柱 [超级前台]sprinbboot maven superdesk-app 记录 [信息有用] [环境准备] [基本完成] [sebp/elk] 给已创建的Docker容器增加新的端口映射 - qq_30599553的博客 - CSDN博客 [正在研究] Elasticsearch, Logstash, Kibana (ELK) Docker image documentation elasticsearch centos 安装记录 及 启动手记 正式服务器 39 elasticsearch 问题合集 不断更新 6.1.1 | 6.5.1 两个版本 博客程序 - 测试 - bug记录 等等问题 laravel的启动过程解析 - lpfuture - 博客园 OAuth2 Server PHP 用 Laravel 搭建带 OAuth2 验证的 RESTful 服务 | Laravel China 社区 - 高品质的 Laravel 和 PHP 开发者社区 利用Laravel 搭建oauth2 API接口 附 Unauthenticated 解决办法 - 煮茶的博客 - SegmentFault 思否 使用 OAuth2-Server-php 搭建 OAuth2 Server - 午时的海 - 博客园 基于PHP构建OAuth 2.0 服务端 认证平台 - Endv - 博客园 Laravel 的 Artisan 命令行工具 Laravel 的文件系统和云存储功能集成 浅谈Chromium中的设计模式--终--Observer模式 浅谈Chromium中的设计模式--二--pre/post和Delegate模式 浅谈Chromium中的设计模式--一--Chromium中模块分层和进程模型 DeepMind 4 Hacking Yourself README.md update 20211011
Laravel China 简书 知乎 博客园 CSDN博客 开源中国 Go Further Ryan是菜鸟 | LNMP技术栈笔记 云栖社区-阿里云 Netflix技术博客 Techie Delight Linkedin技术博客 Dropbox技术博客 Facebook技术博客 淘宝中间件团队 美团技术博客 360技术博客 古巷博客 - 一个专注于分享的不正常博客 软件测试知识传播 - 测试窝 有赞技术团队 阮一峰 语雀 静觅丨崔庆才的个人博客 软件测试从业者综合能力提升 - isTester IBM Java 开发 使用开放 Java 生态系统开发现代应用程序 pengdai 一个强大的博主 HTML5资源教程 | 分享HTML5开发资源和开发教程 蘑菇博客 - 专注于技术分享的博客平台 个人博客-leapMie 流星007 CSDN博客 - 舍其小伙伴 稀土掘金 Go 技术论坛 | Golang / Go 语言中国知识社区
最新评论