Opengl es 移动GPU上的扩展浮点精度
我正在尝试使用OpenGLES2.0在gpu上计算图像的梯度向量场。我找到了它的一个cpu实现,并将其与我的gpu实现进行了比较。这里的挑战是cpu实现依赖于java类型的浮点(32位),而我的gpu实现使用的是lowp浮点(8位)。我知道我可以使用mediump或highp来获得更好的结果,但我仍然希望继续使用lowp float来确保我的代码能够在最差的硬件上运行 计算梯度向量场的前几个步骤非常简单:Opengl es 移动GPU上的扩展浮点精度,opengl-es,opengl-es-2.0,gpu,floating-point-precision,post-processing,Opengl Es,Opengl Es 2.0,Gpu,Floating Point Precision,Post Processing,我正在尝试使用OpenGLES2.0在gpu上计算图像的梯度向量场。我找到了它的一个cpu实现,并将其与我的gpu实现进行了比较。这里的挑战是cpu实现依赖于java类型的浮点(32位),而我的gpu实现使用的是lowp浮点(8位)。我知道我可以使用mediump或highp来获得更好的结果,但我仍然希望继续使用lowp float来确保我的代码能够在最差的硬件上运行 计算梯度向量场的前几个步骤非常简单: 计算归一化灰度(红色+绿色+蓝色)/3.0 计算边缘贴图(右像素左像素)/2.0和(上像素
vec2 split(float a)
{
float t = a * (2e-8+1.0);
float aHi = t - (t -a);
float aLo = a - aHi;
return vec2(aHi,aLo);
}
vec2 twoProd(float a, float b)
{
float p = a * b;
vec2 aS = split(a);
vec2 bS = split(b);
float err = ( ( (aS.x * bS.x) - p) + (aS.x * bS.y) + (aS.y * bS.x) ) + (aS.y * bS.y);
return vec2(p,err);
}
vec2 FMAtwoProd(float a,float b)
{
float x = a * b;
float y = a * b - x;
return vec2(x,y);
}
vec2 div(vec2 a, vec2 b)
{
float q = a.x / b.x;
vec2 res = twoProd( q , b.x );
float r = ( a.x - res.x ) - res.y ;
return vec2(q,r);
}
vec2 div(vec2 a, float b)
{
return div(a,split(b));
}
vec2 quickTwoSum(float a,float b)
{
float s = a + b;
float e = b - (s-a);
return vec2(s,e);
}
vec2 twoSum(float a,float b)
{
float s = a + b;
float v = s - a;
float e = ( a - (s - v)) + ( b - v );
return vec2(s,e);
}
vec2 add(vec2 a, vec2 b)
{
vec2 s = twoSum(a.x , b.x);
vec2 t = twoSum(a.y , b.y);
s.y += t.x;
s = quickTwoSum(s.x,s.y);
s.y += t.y;
s = quickTwoSum(s.x,s.y);
return s;
}
vec2 add(vec2 a,float b)
{
return add(a,split(b));
}
vec2 mult2(vec2 a,vec2 b)
{
vec2 p = twoProd(a.x,b.x);
p.y += a.x * b.y;
p.y += a.y * b.x;
p = quickTwoSum(p.x,p.y);
return p;
}
vec2 mult(vec2 a,float b)
{
return mult2(a, split(b));
}
显然,我在这里肯定做错了什么,或者错过了一些基本的概念,因为无论是使用简单运算还是扩展浮点运算,我都得到了相同的结果
这里的挑战是cpu实现依赖于java类型的浮点(32位),而我的gpu实现使用的是lowp浮点(8位)
lowp
实际上并不意味着用于浮点运算的位数。它更多地涉及必须可表达的值的范围和最小可分辨值(精度)-您可以使用它来计算最小位数,但GLSL从来没有这样讨论过
目前,不做任何花哨的事情,我能够准确地模拟步骤1,这样cpu实现的图像结果与gpu的图像结果相同
这是幸运的,因为您描述中的一个直接问题来自这样一个事实,lowp
只保证表示范围[-2.0,2.0]内的值。如果试图通过将低精度浮点值除以3(如步骤1所示)来规范化该值,则该操作可能有效,也可能无效。在最坏的情况下,这将不起作用,因为浮点值永远不会达到3.0。但是,在某些GPU上,它可能会起作用,因为lowp
和mediump
之间可能没有区别,或者GPU的lowp
可能超过GLSL ES 1.00规范中概述的最低要求
。。。尽管如此,我还是希望继续使用lowp float来确保我的代码能够在最差的硬件上运行
如果您的目标是尽可能低的终端硬件,请记住ES 2.0需要在所有着色器阶段提供mediump
支持。lowp
可能带给您的唯一好处是某些GPU的性能有所提高,但任何可以承载ES 2.0的GPU都支持中精度浮点运算,并且您的算法需要的范围大于lowp
保证