顶点与片段着色器中highp、lowp、mediump的选择及最佳实践与性能差异
Great question! Precision qualifiers are one of those underrated details that can swing both visual quality and shader performance—especially on mobile GPUs, where every cycle counts. Let’s break down when and how to pick each one, plus best practices and performance tradeoffs.
First: Quick Primer on Each Precision
Let’s start with the basics of what each qualifier means (note: exact bit depths can vary by GPU, but these are standard):
highp: Highest precision (typically 32-bit floating point, equivalent to a CPU'sfloat). Has the largest range and smallest error.mediump: Medium precision (usually 16-32 bits, most commonly 16-bit for mobile). Balances range, error, and performance.lowp: Lowest precision (8-16 bits, often 8-bit for color values). Tiny range, highest error, but fastest to compute.
Vertex Shader: Prioritize Accuracy Over Performance
Vertex shaders process far fewer elements (thousands of vertices vs. millions of fragments) so performance hits from high precision are negligible. Accuracy is way more important here—bad precision can break your geometry.
- Use
highpfor:- World-space positions, view/projection matrix calculations (large coordinate ranges risk precision loss with lower qualifiers)
- Complex vertex animations (e.g., bone skinning matrix multiplications)
- Any calculation where small errors would lead to visible model distortion
- Consider
mediumpfor:- Simple 2D UI vertices (small coordinate ranges like 0-1080 where precision loss won’t be noticeable)
- Vertex color values (if you don’t need subtle color gradients)
- Almost never use
lowp: Vertex data volume is too small to gain meaningful performance, and the risk of precision errors (like vertex jitter) is too high.
Fragment Shader: Balance Accuracy and Performance
Fragment shaders are where precision choices make the biggest performance impact—each frame can process millions of fragments, so even small per-fragment savings add up.
- Use
highpfor:- PBR lighting calculations (reflection, refraction, or specular highlights that depend on precise world-space values)
- Parallax or displacement mapping (requires precise texture coordinate offsets)
- Fog calculations based on world-space position (large ranges need high precision to avoid banding)
- Use
mediumpfor:- Most standard effects: diffuse lighting, basic texture sampling, 2D color blending, simple shadow maps
- UV coordinates for standard textures (unless you’re dealing with huge texture atlases that need extra precision)
- Use
lowpfor:- Color values (RGBA—since colors live in a 0-1 range, 8-bit precision is more than enough for human perception)
- Alpha values, brightness adjustments, or mask calculations (simple 0-1 range operations)
- Any calculation where the output only needs to represent a narrow range of values
Best Practices
- Stick to the "minimum necessary precision" rule: Always start with the lowest precision that doesn’t hurt visual quality, especially in fragment shaders.
- Set a default precision: At the top of your shader, use
precision mediump float;(or whatever makes sense for your use case) to avoid repeating qualifiers for every variable. Override only when needed. - Test on target hardware: Mobile GPUs are far more sensitive to precision choices than desktop GPUs. Test with your target devices to catch precision-related bugs (like banding or geometry jitter) early.
- Watch for overflow:
lowphas an extremely narrow range (often ±2.0). If you feed a value outside that range into alowpvariable, it’ll clamp or become NaN—leading to weird visual glitches. - Don’t skimp on vertex shader precision: As mentioned earlier, vertex shader performance costs are minimal, so prioritize accuracy here to avoid broken geometry.
Performance Differences
- Fragment shader impact is significant: On mobile GPUs,
lowp/mediumpoperations can be 2-3x faster thanhighp—they use fewer ALU cycles and less memory bandwidth. On desktop GPUs, the gap is smaller, but it’s still good practice to optimize. - Vertex shader impact is negligible: Since vertex counts are orders of magnitude lower than fragment counts, even using
highpeverywhere in a vertex shader won’t move the performance needle. - Memory bandwidth savings: Lower-precision variables take up less memory. Pairing
lowpwith low-precision texture formats (like RGBA8) reduces the amount of data the GPU needs to read from memory, which is another big win on mobile.
内容的提问来源于stack exchange,提问作者WayneNWayne

