用Compute Shader实现移动端Tiled Deferred Lighting

解读

国内一线/二线游戏公司(腾讯、网易、米哈游、叠纸、鹰角等)在中高端3D项目(开放世界、MMO、重度ARPG)的面试里,常把“移动端Tiled Deferred Lighting”作为区分Senior与Expert的试金石。
面试官真正想听的不是“能跑”,而是:

  1. 理解移动端GPU的TBR/TBDR架构(PowerVR/Mali/Adreno)并知道为什么传统Deferred在移动端会触发大量G-Buffer带宽;
  2. 能用Compute Shader把光源裁剪、光照计算、Tile共享内存全部搬到On-Chip Memory,把带宽压到1/10
  3. 在Unity里落地过,能给出Shader Variant、Metal/OpenGL ES3.1兼容性、iOS/Android差异化的调优经验;
  4. 量化过收益:DrawCall、GPU Time、Bandwidth、发热、帧率,用Snapdragon Profiler/Perfetto/Mali Graphics Debugger看过真实数据。
    回答时务必先讲瓶颈->再讲算法->再讲工程->再讲数据,否则会被直接打断。

知识点

  1. 移动端TBR/TBDR与带宽瓶颈
    • Tile Memory只有十几KB,G-Buffer 4张RT=64Byte/pixel,1080p一帧就超标;
    • Deferred=每像素每光源一次G-Buffer读,带宽爆炸。
  2. 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回退。
  3. Tiled Deferred核心算法
    • Z-PrepassHi-Z生成深度纹理;
    • Compute Shader一趟Dispatch按16×16 Tile遍历,Min/Max ZReduce得到锥体;
    • 光源裁剪:球-锥体相交,Sphere-Frustum TestCohen-Sutherland加速;
    • Tile内共享光源索引列表Shared Memoryuint lightIndices[MAX_LIGHT_PER_TILE=128]
    • ShadingBlinn-PhongPBR(Mobile-Optimized)Tile内一次G-Buffer读N·L/N·VHalf-Vector优化;
    • 输出直接写RTHandleR11G11B10_UFloat无Alpha节省带宽。
  4. Unity工程落地细节
    • SRP Batcher兼容:Compute Shader里不能采样unity_SpecCube0,需要预卷积IBLTexture2DArray
    • HDR Encoding:iOS用RGBM,Android用LogLuvShader Variant#pragma multi_compile _ TILE_SIZE_16 TILE_SIZE_32
    • 发热控制Tile List Build30 fps时**≤0.8 ms**(SD 865),光源上限=256
    • Fallback:GPU不支持CS时回退到Forward+,**宏SHADER_API_GLES<3.1**分支。

答案

(面试现场建议用**“总-分-总”口语化表述,控制在4分钟内,关键数字加重**)

“我在上一个开放世界项目里,把场景光源从64盏Forward DrawCall降到单Pass Tiled Deferred,GPU Time从9.3 ms→3.1 ms,温度降4.7 ℃
核心分三步:

  1. 数据准备
    Unity SRPDrawRenderers把深度、法线、高光、材质ID一次性画到R11G11B10+RGBA8的2张RT,带宽24 Byte/pixel
  2. Compute Shader
    线程组16×16×1,共享内存28 KB
    • Min/Max ZGroupMemoryBarrierWithGroupSyncwarp-level reducefloat2zMinMax
    • 光源裁剪:CPU端把256盏光源建成SOA结构(pos+radius+color),ComputeBuffer 16 KB,Sphere-Frustum4-bit ClipMask剔除率92%
    • 光照计算BRDFLambert+Cook-Torrance近似F0从材质ID查表,sharedMemlightIndicesLoop 128次,纹理采样0次
  3. 输出与后续
    结果写回R11G11B10_UFloatAlpha通道复用SSAO强度Tile边缘0.5像素Neighborhood Clamp防止漏光。
    兼容性上,iOS A9+MTLFeatureSet_iOS_GPUFamily3_v1Android GLES3.1+GL_OES_texture_storageShader Variant#pragma kernel CSMain TILE_SIZE=16不支持时回退Forward+
    最终GFXBench Manhattan 3.1帧率**+38%Snapdragon Profiler带宽从5.2 GB/s→0.6 GB/s**。”

拓展思考

  1. Clustered Deferred在移动端是否值得?
    光源>512场景纵深>1 km时,Z轴切8层可把每Tile光源数再降30%,但Shared Memory超32 KB,需要2-passIntel扩展的SLM目前国产项目只有《崩坏:星穹铁道》PC版开启移动端仍用Tiled
  2. Variable Rate Shading(VRS)+Tiled Deferred
    高通Snapdragon 8 Gen 2支持1×2/2×1/2×2VRSTile边缘用1×1内部用2×2,可把Shading Rate再降40%,但Unity 2022 LTS需要自定义RenderPass插入Subpass Load2023.2才官方支持
  3. GPU Driven+Tiled Deferred
    光源裁剪搬到GPU端剔除,用Indirect DispatchPer-Tile Light CountCPU零介入Unity 2023的GPU Resident Drawer已给出实验接口明年项目可落地