移动平台GPU硬件兼容性问题(持续补充)

露米 Lumi

修炼图形学中。。。
写篇文章收集记录下一些移动平台的GPU 硬件兼容性问题,防止自己忘了。欢迎大家补充。
PowerVR系列
1. PowerVR GE8320的UBO大小问题
- 运行设备 : Oppo和Vivo的多款手机,例如Oppo A8, vivo Y81s, vivo Y93等
- GFX Version : OpenGL ES 3.0
- 症状描述 : 单个UBO大小超过大概15000 bytes后,当次的DrawCall会出现花屏/不显示等问题。后续的DrawCall可能随机性出问题。
- 分析 : OpenGL ES 3.0的规范上声明 每个fragment shader能同时使用至少12个UBO,单个UBO的最小的大小上限是16KB。GE8320官方声明支持到OpenGL ES 3.2,因此它没有满足 OpenGL ES 3.0规范声明的ubo最小的大小。
- 解决方法 : 根据配置减配UBO大小。
2. PowerVR GE8320的discard和动态循环导致的死循环问题。
- 运行设备 :Oppo和Vivo的多款手机,例如Oppo A8, vivo Y81s, vivo Y93等
- GFX Version : OpenGL ES 3.0
- 症状描述 : 当Shader中的循环次数来自贴图的读取,而不是编译期或uniform变量确定的值时,同时配合discard行为可能会陷入死循环,导致ps shader无法结束。例如 下面的Alpha test配合Cluster Shading的例子,就会陷入死循环。
// Alpha Test Enabled
if (mtlAlpha < ALPHA_TEST_CLAMP_VALUE)
discard;
// ... other code
uint lightCount = ClusterLightTable.Load(index).r;
for(uint i = 0; i < lightCount; ++i)
// do some per light caculations.
}
-
分析
:由于显卡的结构设计是单指令多发射,显卡的单个处理单元同时在跑多个pixel的pixel shader。在部分老的GPU上,当某个pixel被discard 或者在 ps_main中return后,该pixel的pixel shader并不会停止执行(虽然最后结果会被丢弃)。 我猜测,这些GPU刚好还做了一些优化,例如忽略了discard的pixel的Texture Load的指令,导致循环变量
lightCount
是一个随机的值,因此陷入了一个巨大的循环,进而 导致 循环展开指令爆炸或者执行时间太长。 - 解决方法 : 针对这种指令发射逻辑的GPU,采用discard后置。具体看下面这个代码:
#if !ALPHA_TEST_DELAY
if (mtlAlpha < ALPHA_TEST_CLAMP_VALUE)
discard;
#endif
// ... other code
uint lightCount = ClusterLightTable.Load(index).r;
for(uint i = 0; i < lightCount; ++i)
// do some per light caculations.
#if ALPHA_TEST_DELAY
if (mtlAlpha < ALPHA_TEST_CLAMP_VALUE)