WebGL Shader precision on MacBook Pro vs iPhone

Screenshot 2021-03-01 at 14.39.19.png

Photo by David Monje on Unsplash

I learned something new today. When developing in WebGL, you are required to set a default precision for the fragment shader. Here are the options:

precision lowp float;
precision mediump float;
precision highp float;

I read somewhere that lower precision calculations are faster, so if the result is the same you should attempt to use lowp if possible. I switched shademap.app to use lowp precision and everything looked good UNTIL I checked it on the iPad and my iPhone. It was broken.

Both were using lowp, how could this be? Well, it turns out that the precision is not identical across hardware. (I suspect the reason is that the iPhone uses an Apple chip while the MacBook uses an Intel chip). The lack of precision was causing my shade calculations to lose accuracy and the final result was incorrect.

Here is what lowp, mediump, highp correspond to on each device:

MacBook Pro (2018)iPhone SE
lowp precision: 23
rangeMin: 127
rangeMax: 127
precision: 10
rangeMin: 15
rangeMax: 15
mediumpprecision: 23
rangeMin: 127
rangeMax: 127
precision: 10
rangeMin: 15
rangeMax: 15
highpprecision: 23
rangeMin: 127
rangeMax: 127
precision: 23
rangeMin: 127
rangeMax: 127

As you can see, if you want the iPhone/iPad and MacBook Pro to use the same precision and range, you will need to set your fragment shader to highp.

Using another device? You can check its precision settings here or use the following code:

const canvas = document.createElement('canvas');
const div = document.createElement('div');
document.body.append(div);
const gl = canvas.getContext('webgl');

const types = {
  lowp: gl.LOW_FLOAT,
  mediump: gl.MEDIUM_FLOAT,
  highp: gl.HIGH_FLOAT,
};

let output = '';
for (x in types) {
  const { precision, rangeMax, rangeMin } = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, types[x])
  output += x + ': ' + JSON.stringify({precision: precision, rangeMin: rangeMin, rangeMax: rangeMax}, null, 2) + '\n';
}
div.innerText = output;
 
2
Kudos
 
2
Kudos

Now read this

ShadeMap 2021 Wrap Up

Development # A big change happened this fall. Right around the one-year mark I finally succeeded in migrating Shade Map (shademap.app) onto a vector based map. Up until this point I used tiled image maps which downloaded many small,... Continue →