gonzojive
gonzojive

Reputation: 2216

What is the precision of highp floats in GLSL ES 2.0 (for iPhone/iPod touch/iPad)?

I have a shader that ideally needs 28 bits of mantissa, though I can use less and degrade performance. How can I determine what the precision of 'highp' is in OpenGL ES? It's probably an FP24, with 16bits mantissa, but I cannot figure out for sure or how to ask OpenGL. Any ideas?

Upvotes: 34

Views: 41402

Answers (3)

Brad Larson
Brad Larson

Reputation: 170309

From the OpenGL ES Shading Language reference:

  • highp - 16-bit, floating point range: −262 to 262, integer range: −216 to 216
  • mediump - 10 bit, floating point range: −214 to 214, integer range: −210 to 210
  • lowp - 8 bit, floating point range: −2 to 2, integer range: −28 to 28

In OpenGL ES 3 these guarantees have been upgraded, see the GLSL ES 3.00 spec:

  • highp - 24-bit, floating point range: −2126 to 2127, signed integer range: −231 to 231−1, unsigned integer range: 0 to 232−1
  • mediump - 10 bit, floating point range: −214 to 214, signed integer range: −215 to 215−1, unsigned integer range 0 to 216−1
  • lowp - 8/9 bit (signed/unsigned), floating point range: −2 to 2, signed integer range: −28 to 28−1, unsigned integer range 0 to 29−1

Upvotes: 39

Steven Lu
Steven Lu

Reputation: 43417

In my testing on my line of expensive toys:

For both ints and floats, the precisions and ranges across fragment and vertex shaders are the same.

So I will not list all combinations exhaustively.

Also note that precision of ints is defined to be always 0.

PowerVR SGX543MP3 (iPhone 5):

  • Floats
    • Low: precision = 8, range = 0 to 0 (Not sure, but I think this means that we cannot expect a lowp to actually be able to represent a value reaching exactly 2 or -2, I don't really know of a great way to test this, nor should we over-concern ourselves with these limitations, just use mediump when this could ever be an issue)
    • Medium: precision = 10, range = 15 to 15 (meets spec)
    • High: precision = 23, range = 127 to 127 (exceeds spec)
  • Ints
    • Low: range = 23 to 23 (exceeds spec)
    • Medium: range = 23 to 23 (exceeds spec)
    • High: range = 23 to 23 (exceeds spec)

A7 & PowerVR G6430 (iPad Air):

  • Floats
    • Low: precision = 10, range = 15 to 15 (exceeds spec)
    • Medium: precision = 10, range = 15 to 15 (meets spec)
    • High: precision = 23, range = 127 to 127 (exceeds ES 2.0 spec, meets 3.0 spec)
  • Ints
    • Low: range = 15 to 14 (exceeds spec)
    • Medium: range = 15 to 14 (exceeds ES 2.0 spec, meets ES 3.0 spec)
    • High: range = 31 to 30 (exceeds ES 2.0 spec, meets ES 3.0 spec)

A8 & PowerVR GX6450 (iPhone 6 Plus):

  • Floats
    • Low: precision = 10, range = 15 to 15 (exceeds spec)
    • Medium: precision = 10, range = 15 to 15 (meets spec)
    • High: precision = 23, range = 127 to 127 (exceeds ES 2.0 spec, meets 3.0 spec)
  • Ints
    • Low: range = 15 to 14 (exceeds spec)
    • Medium: range = 15 to 14 (exceeds ES 2.0 spec, meets ES 3.0 spec)
    • High: range = 31 to 30 (exceeds ES 2.0 spec, meets ES 3.0 spec)

Here is an example of how you might query the values.

int range[2], precision;
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT, range, &precision);
NSLog(@"Fragment shader high precision float range: %d %d precision: %d", range[0], range[1], precision);
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT, range, &precision);
NSLog(@"Fragment shader medium precision float range: %d %d precision: %d", range[0], range[1], precision);
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_LOW_FLOAT, range, &precision);
NSLog(@"Fragment shader low precision float range: %d %d precision: %d", range[0], range[1], precision);

glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_INT, range, &precision);
NSLog(@"Fragment shader high precision int range: %d %d precision: %d", range[0], range[1], precision);
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_MEDIUM_INT, range, &precision);
NSLog(@"Fragment shader medium precision int range: %d %d precision: %d", range[0], range[1], precision);
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_LOW_INT, range, &precision);
NSLog(@"Fragment shader low precision int range: %d %d precision: %d", range[0], range[1], precision);

glGetShaderPrecisionFormat(GL_VERTEX_SHADER, GL_HIGH_FLOAT, range, &precision);
NSLog(@"Vertex shader high precision float range: %d %d precision: %d", range[0], range[1], precision);
glGetShaderPrecisionFormat(GL_VERTEX_SHADER, GL_MEDIUM_FLOAT, range, &precision);
NSLog(@"Vertex shader medium precision float range: %d %d precision: %d", range[0], range[1], precision);
glGetShaderPrecisionFormat(GL_VERTEX_SHADER, GL_LOW_FLOAT, range, &precision);
NSLog(@"Vertex shader low precision float range: %d %d precision: %d", range[0], range[1], precision);

glGetShaderPrecisionFormat(GL_VERTEX_SHADER, GL_HIGH_INT, range, &precision);
NSLog(@"Vertex shader high precision int range: %d %d precision: %d", range[0], range[1], precision);
glGetShaderPrecisionFormat(GL_VERTEX_SHADER, GL_MEDIUM_INT, range, &precision);
NSLog(@"Vertex shader medium precision int range: %d %d precision: %d", range[0], range[1], precision);
glGetShaderPrecisionFormat(GL_VERTEX_SHADER, GL_LOW_INT, range, &precision);
NSLog(@"Vertex shader low precision int range: %d %d precision: %d", range[0], range[1], precision);

It is not clear to me yet whether you can expect tangible performance improvements by choosing a lower-precision type (Even on some phones that are now 3 years old).

It's clear that the trend is towards convergence with desktop hardware as it can be seen that the recent GPU's have completely eliminated the 8 bit types and are recycling the mediump ones for lowp.

Upvotes: 17

Chris Dodd
Chris Dodd

Reputation: 126130

You want GetShaderPrecisionFormat to query the range and precision of of shader types

int range[2], precision;
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT, range, &precision);

will give you the range and precision of highp float.

Upvotes: 14

Related Questions