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

Yosemite: Snake Dike

Snake Dike route (red section was roped, blue was unroped) We woke up just after 3am. Trying to stay quiet, we put on our packs and made our way out of the sleepy campground. After a mile on flat ground we started the 2000 foot ascent to... Continue →