移动端GPU带宽优化:纹理压缩与后处理降载实战

发布时间:2026/9/12 14:25:38
移动端GPU带宽优化:纹理压缩与后处理降载实战 上周优化一个植物园场景的Demo真机跑了两分钟机身就开始烫手。截帧一看顶点数不算夸张DrawCall也压得住GPU频率却稳稳顶在最高档。真正把我的带宽预算掏空的是纹理采样和后处理这两个环节。我习惯把这两个家伙称为“搬运量最大的两个惯犯”——它们的发热贡献常常被开发者低估因为从表面上它们既不像DrawCall那么扎眼也不像顶点数那样直观可见但每一帧都在内存里疯狂搬运数据。这篇是发烫优化系列的第4篇。前面聊过网格、阴影和过早优化这些方向这篇专门盯着纹理和后处理这两座带宽大山。文章会把“搬运量”这件事拆开讲清楚它到底搬了什么、怎么计算、怎么降下来以及我在实际项目里踩过的坑和实测数据。无论你是做Unity还是UE做手游还是AR应用纹理压缩、Mipmap、半分辨率后处理、合并Pass这些手段都值得对着自己的项目重新排查一遍。1. 发烫的账本GPU功耗里的“搬运费”1.1 计算和带宽谁是发热主力移动GPU的功耗来源大致可以分成两类一类是计算也就是Shader里跑了多少条指令ALU在干活另一类是带宽也就是GPU从显存里读了多少数据、往显存里写了多少数据。很多开发者会把发热归因于“特效太复杂”“Shader太贵”但实测下来在移动端带宽往往是比计算更早撞上的瓶颈。为什么带宽对发热这么敏感因为数据的“搬运”要经过内存控制器、总线、缓存这些物理链路每搬一次数据这些电路都在工作都在耗电。更关键的是移动端的LPDDR内存带宽远没有桌面端那么富裕。一块高通骁龙平台的LPDDR4X理论带宽通常也就二三十GB每秒实际可用还要再打折扣。而GPU核心在同样时间内能计算的FLOPs却在不断膨胀结果就是“算得越来越快但喂数据的路就那么宽”谁在带宽上贪得多谁就把手机变成暖手宝。1.2 纹理和后处理为什么是搬运最多的环节把一帧画面的带宽开销列出来纹理采样几乎必然排第一。一个复杂的PBR材质一张基础色贴图、一张法线贴图加上粗糙度、金属度、AO可能还有细节贴图每个像素要采样好几张而且在延迟渲染或TAA等后期效果里还可能做重复采样带宽就像流水一样哗哗往外流。后处理则是另一类搬运大户它自己不产生原始画面却把整张屏幕图像在多个RenderTarget之间来回倒腾。每一个全屏Pass都要先读一遍整张RT写一遍另一张RT。一个超标的后处理链等于让GPU把屏幕数据当货物一样反复装卸。这两个“惯犯”叠加起来有时候能占掉整帧带宽的50%以上。这也是我写这篇文章的原因——想降发热先盯住这两个地方往往性价比最高。2. 纹理在缓存和显存之间反复横跳2.1 采样一次纹理GPU到底在搬多少数据先看一个基础公式每一次纹理采样GPU都要把纹理所占的显存数据读进缓存。这个数据量取决于纹理格式和大小。比如一张2048×2048的RGBA32贴图未压缩时占2048×2048×4字节约等于16MB。如果在屏幕上铺满这张贴图每帧至少要完整读一遍也就是16MB的搬运量。按60帧算每秒就是接近1GB的纯纹理读取带宽。实际开销还要加码。三线性过滤采样会一次读多层Mipmap各向异性过滤更夸张采样次数成倍上升同一张纹理被多个物体重复引用时缓存命中率高还好如果图集安排不当、纹理过大导致缓存频繁失效GPU就要反复去显存里搬同一块数据。用生活类比就是一道菜本来能在厨房灶台上直接取用食材你非要把冰箱搬到客厅去来回跑三趟。所以纹理优化的核心不是“贴图画质好不好看”而是“每一次采样到底搬了多少不该搬的数据”。这是理解后面所有操作的大前提。2.2 纹理压缩性价比最高的降压药纹理压缩是移动端发热优化里投入产出比极高的一步。先把一个概念说清楚这里说的压缩不是打Zip、PNG那种文件层面的压缩而是GPU硬件可以直接解码的压缩格式。它的价值在于纹理在显存里本身就变小了那每次采样读进缓存的数据自然也变小带宽、缓存命中率、发热都一起受益。移动端主流格式就两类ETC2和ASTC。ETC2是Android从4.3开始官方支持的标准格式RGBA版本的位率是8bpp每像素8位ASTC是更新的标准普及度已经是现代移动设备的主流从4×4到12×12分了很多档位。用表格对比一下纹理格式位率1张2048×2048贴图大小相对RGBA8888开销RGBA888832 bpp16 MB100%ETC2 RGBA88 bpp4 MB25%ASTC 4×48 bpp4 MB25%ASTC 6×63.56 bpp约1.8 MB约11%ASTC 8×82 bpp1 MB6.25%从这张表能直观看出一张RGBA8888的贴图压成ASTC 8×8显存占用直接降为原来的1/16。我们项目里做过一次全量重压缩主要场景贴图从RGBA32切到ASTC 6×6和8×8GPU整体带宽降了将近40%。注意ASTC对透明纹理的处理比ETC2好很多不用像ETC2那样担心Alpha通道的额外开销。如果纹理本身是UI或带透明边缘的粒子优先考虑ASTC 4×4或6×6质量足够效果稳定。另外要提醒一句纹理压缩格式也要看目标设备范围。虽然ASTC现在是主流但一些老设备或者模拟器只支持ETC2甚至不完全支持ASTC。项目里要做纹理格式的平台映射iOS全系基本可以无脑ASTCAndroid按OpenGL ES版本分级保留一个ETC2回退档。我用过Unity的Texture Import Settings里的平台Override也用过Addressables的格式分组都能做到自动替换关键是测试时别只在真机旗舰机上验证多找几台中低端机刷一刷。2.3 Mipmap、图集与尺寸控制的隐藏收益纹理压缩解决的是“单位面积数据量”问题Mipmap解决的则是“采样密度匹配”问题。当地面离摄像机很远时屏幕上可能只有几个像素但GPU却会去读整张4096贴图读进来的数据绝大部分用不上这种浪费就是典型的无效搬运。生成Mipmap之后GPU会自动选择与屏幕像素尺寸接近的那一层Mip读入的数据量大幅下降。虽然Mipmap会让纹理总显存增加大约33%但换来的是带宽的大幅下降和采样质量的提升还能减少远处闪烁对移动端来说极端划算。我见过不少项目为了省显存不生成Mipmap结果就是在Profiler里看到带宽爆表发热和掉帧一起找上门怎么看都不划算。图集Texture Atlas和纹理尺寸控制同样影响搬运量。过大的图集比如超过2048甚至4096的单张纹理很容易突破GPU缓存行的有效命中范围。移动GPU的纹理缓存是按块管理的纹理越大同样一块屏幕区域需要读入的数据越分散。我做UI时会尽量把图集控制在2048以内场景贴图也按“近景可用大图、远景用中图”的规则做分类减少大纹理在全屏场景里的滥用。顺带提一句像OpenMVS这类三维重建算法生成的纹理贴图动辄单张4096甚至8192导入项目做展示或者放AR里落地时不做重压缩和重排发热是肉眼可见的猛。这类贴图要先做匀色、重分UV、再压到ASTC 8×8才能在移动端真正用起来。3. 后处理重复搬运全屏数据的惯犯3.1 一张全屏Pass的搬运清单后处理和纹理的发热机制不同。纹理是“每个像素采多次”导致搬运量大后处理则是“整张屏幕图像被反复读写”导致搬运量爆炸。先算一笔账以1080p的屏幕为例一帧全屏图像约207万个像素如果RenderTarget用RGBA16F每像素8字节那读一次全屏RT就是16MB左右的带宽。任何一个全屏后处理Pass都要“读一次RT 写一次RT”也就是搬运32MB左右的数据。按60帧算一个Pass就要吃掉接近2GB/s的带宽。问题是后处理往往不是一个Pass。Bloom要降采样、模糊、升采样算下来四五个Pass起步再加景深、泛光、色调映射、色差、噪点一条后处理链跑下来全屏图像被搬了十几次。哪怕每个Pass单独看都不算贵合起来就是带宽大户。我把这类问题称为“后处理洗手效应”洗个手只要几秒但一天洗十几次水费就开始让人肉疼了。顺便吐槽一句网上搜“后处理”会出来一堆数控加工领域的内容比如五轴后处理、UG后处理判断四轴变化时Z轴回零那是完全不同的应用领域。这篇文章聊的是渲染管线里的后处理别搞混。3.2 用半分辨率砍掉大半搬运量后处理优化的第一个思路是降低参与后处理的像素总量。人眼对高频细节和低频颜色变化的分辨能力是不同的像泛光、景深、体积雾这类低频效果完全可以在半分辨率、甚至四分之一分辨率下计算再升采样回原分辨率。这有个专门的说法叫“频谱分离”把画面拆成高频和低频低频部分用低分辨率处理高频部分保留原分辨率。具体到Bloom我通常的做法是先把原分辨率RT按二分之一降采样一次得到半分辨率图层后续的模糊和迭代全在半分辨率甚至四分之一分辨率上进行最后做一次升采样叠加回原图。这样整套Bloom的像素处理总量可能只有全分辨率的25%到30%带宽压力和发热立刻降下来。景深、泛光、光晕也是同理。需要小心的是半分辨率处理太狠会有画质问题比如高频边缘出现闪烁、模糊结果显得脏。我的经验是模糊半径大了之后视觉上反而能掩盖分辨率不足的问题关键参数是全分辨率到半分辨率的降采样滤镜要选好别用普通点采样用带有小幅高斯权重或者双线性过滤的降采样能缓解很多闪烁。移动端项目里我一般把Bloom的模糊层控制在半分辨率只有特别简单的卡通风格才敢用四分之一。3.3 合并Pass让GPU少跑几趟内存后处理的另一个优化方向是减少全屏Pass的数量让GPU尽量不来回读写字面量。这里有两个层级的手段第一个层级是“MergePass”。很多后处理效果之间是可以合并的比如色调映射、饱和度调整、噪点、暗角、色差这些逐像素处理完全可以写进同一个Shader里在最后一个Pass中一次性完成。做合并之前理清依赖关系很重要哪些效果是输入性依赖需要整张图信息哪些是逐像素独立操作独立操作尽量往后合并。我见过有些项目把Bloom、色调映射、噪点分成了三个单独的Pass一个合并就能把后处理链从9个Pass压到6个。第二个层级是利用移动GPU的TBDR架构特性。移动GPU大多数是基于瓦片渲染的片上有一块高速缓存Tile MemoryRT数据可以被留在片上避免真正写回显存再读出来。在GLES里可以用GL_EXT_shader_framebuffer_fetch扩展实现片上帧缓冲读取在Vulkan里用Subpass在Metal里也有对应的LoadStoreAction配置。这样多个后处理Pass之间数据就只在这个快速缓存里流动内存带宽大幅下降。类似YOLO这类AI检测里的后处理流程如果你把NMS、阈值过滤每个小步骤都拆成单独内核跑显存和计算开销会非常难看图形后处理也是同一套逻辑能在片上完成的工作别折腾到全局内存里。Unity里用Shader可以实现framebuffer fetch但要注意设备兼容性最好做特性的运行时检测直接使用CommandBuffer做Pass串联时也可以利用LoadAction/StoreAction的配置让不必要存储的RT留在瓦片上。这部分的收益非常可观我优化过一个项目的景深把六个Pass改成三个Subpass之后帧时间直接降了将近两毫秒。3.4 机型分级与动态开关策略后处理不是“全有或全无”而是“按设备能力给不同档位”。中低端机连全屏Pass跑起来都吃力更别说叠好几个后处理效果了。我建议给后处理管线配置三档方案高配档开启Bloom、景深、体积雾、完整的色调映射RT格式可以用RGBA16F。中配档只保留Bloom半分辨率和基础色调映射关掉景深和体积雾RT降到RGBA10或RGBA8。低配档顶多做一个极轻量的泛光和LUT调色其他全部关闭。这套配置怎么落地用Unity的话可以将后处理组件挂在同一个Volume上按Quality Level设置不同的Override用UE的话可以用Scalability Level配置。关键是运行时不要做太复杂的实时判断成本要压到最低。还有一点后处理开关要平滑过渡不要让人一眼看出画质掉了。通常我把Bloom的强度调低而不是直接关闭人眼反而不会太敏感。在旗舰机上还可以用动态分辨率系统做进一步控制当帧时间超过警戒值先用后处理半分辨率兜底或者把屏幕分辨率从100%动态降到90%、80%把带宽压力释放出来。这个方向很多厂商都在做Unity的Dynamic Resolution和TAA Upsample方案就是干这个的配合后处理的分档发热控制会从容很多。4. 实操流程一次完整的纹理和后处理降载4.1 摸底找出项目里的带宽大户动手优化之前先要做一次摸底搞清楚到底是谁在烧带宽。我常用的工具链是RenderDoc抓帧看纹理清单Snapdragon Profiler看Adreno的带宽计数器Arm Mobile Studio看Mali GPU的周期和总线占用iOS上则是Xcode的Metal System Trace。没有这些硬核工具时Unity Profiler的GPU模块和Frame Debugger也能提供重要线索。实操第一步是把一帧画面里所有纹理按显存大小排序。方法很简单RenderDoc里导出纹理列表按Size排序一眼就能看到一张4096的RGBA32背景贴图、一套8张2048的法律线贴图、一堆没有压缩的UI图集。这些未经压缩的“巨无霸”通常就是第一波要处理的资源。第二步看后处理链的Pass数量和RT格式。Frame Debugger里能看到每个CommandBuffer干了什么RT有没有反复Load、Store。如果发现一个Bloom链里有五六个全屏全分辨率Pass基本可以确定它是发热的另一大源头。把这两组数据记录下来作为优化前的基线。4.2 纹理降载步骤与参数参考先做能快速见效的“低垂果实”把所有RGBA32/RGBA16纹理切成平台对应的压缩格式。移动平台从ASTC 6×6开始试质量不够再换4×4UI和海报类重点内容用ASTC 4×4场景环境贴图用ASTC 8×8。给所有带距离衰减的场景纹理开启Mipmap。如果担心内存增加把原始Max Size降到合理的上限比如场景大图不超过2048角色贴图不超过1024。检查图集大小超过2048的图集拆小或重新排版。重建类算法产出的纹理如果单张超过4096必须先重投影再压缩。参数上我一般以“视觉上再过5%就接受不了”为界。金属、皮革这类高细节材质用ASTC 6×6天空、地面、墙壁这类大色块材质用ASTC 8×8甚至10×10带渐变的半透明粒子用ASTC 4×4。压缩后要在多台真机上对比截图重点看边缘渗色和黑暗区域的条带感。这个过程中Unity的Compress Texture选项和自带预览窗口就能帮上忙不一定需要额外工具。4.3 后处理管线裁剪方案后处理管线优化的动作我们分三步走第一步砍冗余。把实际上看不出区别的效果删掉比如过强的径向模糊、不必要的色差、重复的泛光叠加。少一个Pass就少一整轮全屏搬运。第二步降分辨率。只保留低频效果走半分辨率路径画面中的锐利边缘和高频细节不要进后处理链。具体做法就是先把RT降采样到半尺寸处理完再升采样混合。第三步合并Pass。把所有逐像素独立的后处理效果合并到最后一个Pass减少中间RT的切换。实际做的时候用Unity的Post Processing V2/V3或者URP的Volume系统可以把效果排序、分层配置然后用一个MergePass统一处理色调映射、饱和度、暗角、噪点。针对不同的后处理链我推荐的掉头顺序是先关体积雾贵又吃内存、再关景深容易诱发眩晕且带宽高、再关Bloom的级数从五级降到三级、再降RT格式RGBA16F改RGBA10。4.4 优化效果实测对比这是我上个月在某个AR展示类项目上得到的实测数据Unity、Android真机目标设备为中端骁龙芯片指标优化前优化后变化纹理显存占用486 MB182 MB下降62%平均GPU带宽11.2 GB/s5.8 GB/s下降48%后处理Pass总数116减少5个GPU帧时间17.5 ms11.2 ms下降36%连续运行15分钟机身温度44.6℃39.2℃下降5.4℃优化动作就是“全量纹理压缩 加Mipmap 拆图集 Bloom降半分辨率 合并后处理Pass”。没有动模型面数也没有砍主场景的特效发热体感从烫手变成温热这个结果对项目来说已经足够有说服力。当然不同GPU的计数器口径不同数值不能跨平台直接比但方向是一致的带宽下降了温度就跟着降。温度测试的姿势也很重要固定亮度、固定场景、跑相同的一段路径录满15分钟看曲线不能拿手摸一下就下结论。数据说话别靠体感。5. 常见问题与排查技巧实录5.1 纹理优化翻车现场问题一ASTC之后边缘出现一圈黑边或亮边。这个常见于带透明通道的贴图原因是RGB边界的颜色外溢进了Alpha边缘区域。解决方式有两种一是把透明材质的纹理在导入前做“预乘Alpha”处理把边缘颜色信息“塞”进透明区域二是在DCC工具里对贴图边缘做几像素的RGB扩张。做UI贴图时我还会在纹理周围留一点透明安全的余量。问题二压到ASTC 8×8后天空出现明显的色带。这是量化位率不足以表现平滑渐变导致的。解决思路不是全部提回6×6而是给天空这类关键渐变纹理单独设高质量档其余继续用8×8。也可以在做渐变时加少量高频抖动噪点让色带在人眼感知上被打散。问题三老设备显示花屏或者紫屏。这是目标设备不支持ASTC导致的兼容性问题。务必要做运行时格式能力检测Android平台按OpenGL ES版本和扩展列表判断不支持ASTC的设备回退到ETC2、甚至RGBA32然后用资源分平台的方式打包别指望大胆一把梭。5.2 后处理优化后的画质陷阱问题一半分辨率Bloom一移动就闪。这是因为降采样时高频光照信息被破坏导致模糊层跟着闪烁。解决要点是降采样先用带滤波的Pass别直接点采样升采样前可以再加一次融和或者采用“两段式高斯”的做法先横向后纵向闪烁会小很多。问题二合并Pass之后颜色不对。这通常是因为合并时把依赖顺序搞错了。色调映射必须在线性空间里做调节的是LDR之后的颜色而Bloom结果要在色调映射之前混入HDR。合并在一个Pass里不是随便写几行代码就行必须把操作顺序标清楚不然会偏色、过曝。我习惯在注释里写清“输入线性HDR → Bloom相加 → 色调映射 → 饱和度 → 暗角 → 噪点”的顺序传阅给同事时也不容易出错。问题三RT格式降低后暗部出现断层。RGBA16F降到RGBA10这个问题的确容易出现。缓解方式尽量避免在RT里做太多次迭代计算后处理链变短之后即使位宽降下来累计误差也会小很多。5.3 排查工具与思路备忘没有专业Profiler时怎么排查一个土办法是“二分法排除”在后处理链里逐级开/关效果看帧时间曲线和发热的差异哪个影响最大就先优化哪个纹理方面也是一样把场景分成几大块一块块替换成压缩纹理对比帧时间。这个方法费点时间但不需要依赖高级工具对调试老项目也够用。工具方面我几乎不用单一的Profiler而是把多个数据交叉着看RenderDoc保证画面细节和纹理正确性Snapdragon/Streamline看带宽和核心占用系统温控的CPU/GPU降频日志看持续负载能力。综合起来才能定位“到底是纹理吃带宽还是后处理吃带宽”这种问题而不是单纯靠猜。排查过程中还有个小技巧把游戏的各性能指标曲线录下来后对齐到同一时间坐标观察是否和发热降频曲线吻合。很多时候你会发现功耗并不是一路高而是跑到几分钟后因为芯片降频突然降低这时候别再加大优化力度先解决“最高功耗点”才对。在动手调纹理和后处理之前先别急着大一统地压默认参数。每个项目都有每个项目的特点地图类场景纹理带宽大FPS竞技场景后处理更容易超标AR应用则两个都跑不掉。最优解往往是在这几个维度之间做平衡而不是单一指标拉满。最后分享一个实用的工作习惯每次做一轮优化都专门记录“优化前后对比截图帧时间带宽温度”存成一份带时间戳的文档。过一个月项目内容更新后再翻出这份基线数据对照能立刻判断是新增功能又引入了发热回退还是环境变化导致的波动。这样每次排查发热问题都不至于从零开始永远有一套持续的量化依据可以依赖。纹理和后处理这两座大山的优化本质就是把“搬运量”这个抽象概念一点点量化、收敛、再验证的过程数据和耐心比任何特效开关都管用。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询