用 short 替代 float 存储顶点数据可使单顶点显存从 32 字节降至 16 字节,百万顶点节省约 16mb,提升缓存命中率并缓解 oom;需严格遵守内存对齐、gpu 格式声明及数据适用边界。

用 short 类型替代 float 存储顶点数据,是图形开发中一种直接、高效且可量化的内存优化手段,尤其适用于移动端和资源受限场景。它不是“省一点是一点”的权宜之计,而是基于数据语义、硬件约束与内存布局三者协同的设计选择。
显存节省原理:从 32 字节到 16 字节
一个典型顶点常含位置(x,y,z)、法线(x,y,z)、纹理坐标(u,v),共 8 个分量:
- 全用
float:8 × 4 字节 = 32 字节/顶点 - 改用
short(归一化后):8 × 2 字节 = 16 字节/顶点,直接减半 - 百万级顶点时,单缓冲区即可节省约 16MB 显存;在 Android UMA 架构下,这等同于降低同等大小的 PSS 内存压力,显著缓解 OOM 风险
- 更小数据体积提升 GPU L1/L2 缓存命中率,对 Mali-G78、Adreno 6xx 等带宽敏感型移动 GPU 效果尤为明显
必须遵守的内存对齐与格式规则
GPU 不会自动推断数据含义——它只按你声明的格式和偏移读取内存。错配即错乱:
- 结构体整体需 4 字节对齐:例如
struct { short x,y,z; }占 6 字节,但缓冲区中会被补齐至 8 字节(末尾加 2 字节填充) - 属性偏移必须对其自身尺寸对齐:
short成员偏移需为偶数,float成员需为 4 的倍数 - OpenGL ES 中必须调用
glVertexAttribPointer(..., GL_SHORT, ...),并明确设置normalized = GL_TRUE(映射 [-1.0,1.0])或GL_FALSE(保留整数值) - Vulkan 中对应格式应为
VK_FORMAT_R16G16B16_SINT等整数格式,不可混用 float 格式
适用与不适用的边界判断
short 是有精度代价的压缩,必须结合数据特性和渲染管线判断是否可用:
-
适合:静态网格位置(经模型空间归一化后)、UV 坐标(缩放后精度达 1/65535)、切线/法线(也可考虑
GL_INT_2_10_10_10_REV更优) - 不适合:世界坐标(动态范围大、需高精度)、骨骼动画中的 world matrix 元素、实时计算的顶点位移(如顶点动画、布料模拟)
- 验证方式:用
adb shell dumpsys meminfo <package></package>对比前后 PSS 变化,比单纯看代码更可靠
配套优化建议:不止于类型替换
单独换 short 有效,但配合其他策略才能发挥最大价值:
- 将多个 short 属性打包进单个
vec4(如法线+切线),减少 attribute slot 数量,降低驱动开销 - 使用 interleaved layout(交错布局),而非 SoA(结构体数组)分离存储,提升缓存局部性
- 对静态顶点缓冲区启用 GPU 内存只读标记(如
GL_STATIC_DRAW或 VulkanVK_BUFFER_USAGE_VERTEX_BUFFER_BIT),帮助驱动做预优化 - 避免在同一个 VBO 中混合 high-precision(float)和 low-precision(short)顶点流,防止对齐复杂度失控











