GLSL ES 2.0(适用于iPhone/iPod touch/iPad)中,highp浮点数的精度是多少?

33
我有一个着色器,理想情况下需要28位尾数,但可以使用较少的位数来降低性能。 如何确定OpenGL ES中“highp”精度是多少?它可能是FP24,具有16位尾数,但我无法确定或询问OpenGL。 有什么想法吗?
3个回答

38

OpenGL ES Shading Language 参考文献

  • highp - 16位,浮点数范围:-262到262,整数范围:-216到216
  • mediump - 10位,浮点数范围:-214到214,整数范围:-210到210
  • lowp - 8位,浮点数范围:-2到2,整数范围:-28到28

在OpenGL ES 3中,这些保证已经升级,请参见GLSL ES 3.00规范

  • highp - 24位,浮点数范围:-2126到2127,有符号整数范围:-231到231-1,无符号整数范围:0到232-1
  • mediump - 10位,浮点数范围:-214到214,有符号整数范围:-215 到 215-1,无符号整数范围0到216-1
  • lowp - 8/9位(有符号/无符号), 浮点数范围:-2到2, 有符号整数范围:-28到28-1,无符号整数范围0到29-1

1
这是标准所要求的最小精度。PVR SGX GPU实际使用的精度也是这个吗? - Minthos
不是这样的。在我的设备上,数字看起来是31位、15位和8位。可能是32、16和8。我不知道最后一位去哪了。 - Minthos
整数似乎无论类型都是24位。 - Minthos
6
GLSL没有强制规定 lowpmediumphighp 所需的位数,只规定了最小值范围和精度。 因此,对于 lowp 浮点值,我们保证其范围为 [-2.0, 2.0],精度为 2.0^-8,但这并不表示系统用多少位来表示它。请注意,本次翻译尽量简明扼要地表达原文含义。 - Andon M. Coleman
如果 highp 的规范为+/- 2^16个整数,那么这是否意味着它具有16位的尾数,并且总位数超过了这个值? - Aaron Franke

17

在我对自己一系列昂贵的玩具进行测试时:

无论是int还是float,在片元着色器和顶点着色器中的精度和范围都是相同的。

因此,我不会详尽列出所有组合。

另外,请注意int的精度始终定义为0。


PowerVR SGX543MP3 (iPhone 5):

  • Floats
    • Low: precision = 8, range = 0 to 0 (推测意味着我们不能指望 lowp 可以精确地表示达到 2-2 的值,不过我不知道如何进行测试,也不应该过于关注这些限制,遇到问题时只需使用 mediump)
    • Medium: precision = 10, range = 15 to 15 (满足规范)
    • High: precision = 23, range = 127 to 127 (超出规范)
  • Ints
    • Low: range = 23 to 23 (超出规范)
    • Medium: range = 23 to 23 (超出规范)
    • High: range = 23 to 23 (超出规范)

A7 & PowerVR G6430 (iPad Air):

  • Floats
    • Low: precision = 10, range = 15 to 15 (超出规范)
    • Medium: precision = 10, range = 15 to 15 (满足规范)
    • High: precision = 23, range = 127 to 127 (超出 ES 2.0 规范, 满足 3.0 规范)
  • Ints
    • Low: range = 15 to 14 (超出规范)
    • Medium: range = 15 to 14 (超出 ES 2.0 规范, 满足 ES 3.0 规范)
    • High: range = 31 to 30 (超出 ES 2.0 规范, 满足 ES 3.0 规范)

A8 & PowerVR GX6450 (iPhone 6 Plus):

  • Floats
    • Low: precision = 10, range = 15 to 15 (超出规范)
    • Medium: precision = 10, range = 15 to 15 (满足规范)
    • High: precision = 23, range = 127 to 127 (超出 ES 2.0 规范, 满足 3.0 规范)
  • Ints
    • Low: range = 15 to 14 (超出规范)
    • Medium: range = 15 to 14 (超出 ES 2.0 规范, 满足 ES 3.0 规范)
    • High: range = 31 to 30 (超出 ES 2.0 规范, 满足 ES 3.0 规范)

以下是查询数值的示例。

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);

我还不确定,在选择低精度类型时是否可以期望获得实质性的性能提升(即使在现在已经有三年历史的某些手机上也是如此)。

很明显,趋势是朝着与桌面硬件的融合方向发展,因为可以看到最近的GPU已完全淘汰了8位类型,并将mediump用于lowp


13
你想使用 GetShaderPrecisionFormat 查询着色器类型的范围和精度。
int range[2], precision;
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT, range, &precision);

这将给出高精度浮点数的范围和精度。


你是不是指的 glGetShaderPrecisionFormatglGetShaderPrecisionType 似乎是一个打字错误。 - gonzojive
glGetShaderPrecisionFormat 确实有效,也许您应该编辑您的回复以修复拼写错误,这样我就可以将其标记为正确。只是为了让下一个人更容易理解。感谢您的答案! - gonzojive
糟糕 - 是我的大脑出了问题,而不是打错字 - 当我检查规范时,只是记错了名称并没有仔细查看。 - Chris Dodd
代码中又出现了一个小错误:range 应该是一个长度为2的整型数组。不过结果还是一样的。 - Minthos
什么决定了精度类型?是操作系统相关的吗?还是GPU相关的?它是否因编程语言或OpenGL版本而异? - Aaron Franke
@AaronFranke:通常取决于GPU,但不同的驱动程序版本也可能会有所不同,特别是如果它们在CPU上执行更多或更少的操作而不是GPU。 - Chris Dodd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接