用Compute Shader实现移动端Tiled Deferred Lighting
解读
国内一线/二线游戏公司(腾讯、网易、米哈游、叠纸、鹰角等)在中高端3D项目(开放世界、MMO、重度ARPG)的面试里,常把“移动端Tiled Deferred Lighting”作为区分Senior与Expert的试金石。
面试官真正想听的不是“能跑”,而是:
- 你理解移动端GPU的TBR/TBDR架构(PowerVR/Mali/Adreno)并知道为什么传统Deferred在移动端会触发大量G-Buffer带宽;
- 你能用Compute Shader把光源裁剪、光照计算、Tile共享内存全部搬到On-Chip Memory,把带宽压到1/10;
- 你在Unity里落地过,能给出Shader Variant、Metal/OpenGL ES3.1兼容性、iOS/Android差异化的调优经验;
- 你量化过收益:DrawCall、GPU Time、Bandwidth、发热、帧率,用Snapdragon Profiler/Perfetto/Mali Graphics Debugger看过真实数据。
回答时务必先讲瓶颈->再讲算法->再讲工程->再讲数据,否则会被直接打断。
知识点
- 移动端TBR/TBDR与带宽瓶颈
- Tile Memory只有十几KB,G-Buffer 4张RT=64Byte/pixel,1080p一帧就超标;
- Deferred=每像素每光源一次G-Buffer读,带宽爆炸。
- Unity Compute Shader在移动端的限制
- Thread Group Shared Memory最大32 KB(iOS A系列),numthreads≤1024;
- OpenGL ES 3.1不支持
RWTexture2D<float4>的rgba16f写,需要rgba8量化或Metal-only分支; - Subgroup在Adreno 530以后才支持,Quad-based warp宽度=16/32,需做Wave Intrinsics回退。
- Tiled Deferred核心算法
- Z-Prepass或Hi-Z生成深度纹理;
- Compute Shader一趟Dispatch按16×16 Tile遍历,Min/Max Z用Reduce得到锥体;
- 光源裁剪:球-锥体相交,Sphere-Frustum Test用Cohen-Sutherland加速;
- Tile内共享光源索引列表,Shared Memory存
uint lightIndices[MAX_LIGHT_PER_TILE=128]; - Shading用Blinn-Phong或PBR(Mobile-Optimized),Tile内一次G-Buffer读,N·L/N·V用Half-Vector优化;
- 输出直接写
RTHandle的R11G11B10_UFloat,无Alpha节省带宽。
- Unity工程落地细节
- SRP Batcher兼容:Compute Shader里不能采样
unity_SpecCube0,需要预卷积IBL成Texture2DArray; - HDR Encoding:iOS用
RGBM,Android用LogLuv,Shader Variant#pragma multi_compile _ TILE_SIZE_16 TILE_SIZE_32; - 发热控制:Tile List Build在30 fps时**≤0.8 ms**(SD 865),光源上限=256;
- Fallback:GPU不支持CS时回退到Forward+,**宏
SHADER_API_GLES<3.1**分支。
- SRP Batcher兼容:Compute Shader里不能采样
答案
(面试现场建议用**“总-分-总”口语化表述,控制在4分钟内,关键数字加重**)
“我在上一个开放世界项目里,把场景光源从64盏Forward DrawCall降到单Pass Tiled Deferred,GPU Time从9.3 ms→3.1 ms,温度降4.7 ℃。
核心分三步:
- 数据准备
用Unity SRP的DrawRenderers把深度、法线、高光、材质ID一次性画到R11G11B10+RGBA8的2张RT,带宽24 Byte/pixel; - Compute Shader
线程组16×16×1,共享内存28 KB:- Min/Max Z:
GroupMemoryBarrierWithGroupSync后warp-level reduce到float2zMinMax; - 光源裁剪:CPU端把256盏光源建成SOA结构(pos+radius+color),
ComputeBuffer16 KB,Sphere-Frustum用4-bit ClipMask,剔除率92%; - 光照计算:BRDF用Lambert+Cook-Torrance近似,F0从材质ID查表,
sharedMem存lightIndices,Loop 128次,纹理采样0次;
- Min/Max Z:
- 输出与后续
结果写回R11G11B10_UFloat,Alpha通道复用作SSAO强度,Tile边缘0.5像素做Neighborhood Clamp防止漏光。
兼容性上,iOS A9+开MTLFeatureSet_iOS_GPUFamily3_v1,Android GLES3.1+跑GL_OES_texture_storage,Shader Variant用#pragma kernel CSMain TILE_SIZE=16,不支持时回退Forward+。
最终GFXBench Manhattan 3.1帧率**+38%,Snapdragon Profiler带宽从5.2 GB/s→0.6 GB/s**。”
拓展思考
- Clustered Deferred在移动端是否值得?
当光源>512或场景纵深>1 km时,Z轴切8层可把每Tile光源数再降30%,但Shared Memory会超32 KB,需要2-pass或Intel扩展的SLM,目前国产项目只有《崩坏:星穹铁道》PC版开启,移动端仍用Tiled。 - Variable Rate Shading(VRS)+Tiled Deferred
高通Snapdragon 8 Gen 2支持1×2/2×1/2×2的VRS,Tile边缘用1×1,内部用2×2,可把Shading Rate再降40%,但Unity 2022 LTS需要自定义RenderPass插入Subpass Load,2023.2才官方支持。 - GPU Driven+Tiled Deferred
把光源裁剪搬到GPU端剔除,用Indirect Dispatch做Per-Tile Light Count,CPU零介入,Unity 2023的GPU Resident Drawer已给出实验接口,明年项目可落地。