一种GL error 501的原因和解决 ----no default precision defined引起

1 问题背景

搞openGL,排查错误的一个好办法,是执行完一句GL调用,就加一句glGetError,如果有错误,这个函数会返回非0值!

本文就是讨论,遇到了,glGetError返回0x501错误的问题。

0x501一般代表,GL上下文环境、shader program等对象索引可能有问题。

1.1 代码背景

vertex shader:

#version 300 es
layout (location = 0) in vec4 vertex;
out vec2 TexCoords;
uniform mat4 u_MVPMatrix;
void main()
{
    
    
    gl_Position = u_MVPMatrix * vec4(vertex.xy, 0.0, 1.0);
    TexCoords = vertex.zw;
}

fragment shader:

#version 300 es 
in vec2 TexCoords;
out vec4 color;
uniform sampler2D text;
uniform vec3 textColor;
void main()
{
    
    
    vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);
    color = vec4(textColor, 1.0) * sampled;
}

shader类:

class Shader
{
    
    
public:
    unsigned int ID;
    // constructor generates the shader on the fly
    // ------------------------------------------------------------------------
    Shader(const char* vertexStr, const char* fragmentStr)
    {
    
    
        DEBUG_LOGCATE();
        ID = GLUtils::CreateProgram(vertexStr, fragmentStr);
    }

    ~Shader() {
    
    }

    // activate the shader
    void use() 
    {
    
     
        glUseProgram(ID); 
    }
    // utility uniform functions
    void setVec3(const std::string &name, const glm::vec3 &value) const
    {
    
     
        glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); 
    }
    //....省略
}

业务代码:

void RenderText(glm::vec3 color) {
    
    
    shader->setVec3("textColor", color);
    checkGLError("RenderText setVec3");
}

void checkGLError(const char *msg) {
    
    
    int error;
    if ((error = glGetError()) != GL_NO_ERROR) {
    
    
        // TODO 抛出异常
        LOGCATE("%s: GL error: %x", msg, error);
    }
}

1.2 问题点

在小米6上,可以正常工作,渲染文字。但是在华为荣耀30上,就不行。日志上,有如下的报错:

03-09 10:42:43.946 10979 11118 E glesdemo: RenderText setVec3: GL error: 501

2 问题解决

2.1 思路

0x501一般代表,GL上下文环境、shader program等对象索引可能有问题。
所以,有理由怀疑,shader是不是没编译成功。

于是向前分析日志,找到一些线索:

03-09 10:42:42.046 10979 11118 E glesdemo: 0:2: S0032: no default precision defined for variable 'TexCoords'

日志报错说,shader变量TexCoords 没有设置精度(precision)!

啥是精度?

简单的说,精度是浮点数的位数。
着色器中的大多数计算是对浮点数进行的。浮点类型有几种变体:float、half 和 fixed(以及它们的矢量/矩阵变体,比如 half3 和 float4x4)。这些类型的精度不同,对应的性能或功耗也不同。

precision包含3种值:highp mediump lowp
区别:

名称 描述
highp 最高精度浮点值;一般是 32 位(就像常规编程语言中的 float)。完整的 float 精度通常用于世界空间位置、纹理坐标或涉及复杂函数(如三角函数或幂/取幂)的标量计算。
mediump 中等精度浮点值;通常为 16 位(范围为 –60000 至 +60000,精度约为 3 位小数)。
lowp 最低精度的定点值。通常是 11 位,范围从 –2.0 到 +2.0,精度为 1/256。半精度对于短矢量、方向、对象空间位置、高动态范围颜色非常有用。

用户可以根据需要定义精度。

shader的精度,会影响画面的细腻程度。顶点着色器,不需要设置,但是片元着色器,一般需要设置!

不同的GPU厂商,对片元着色器的精度的定义不一样,有些直接配了默认值,比如小米6,有些则需要你代码里声明,比如荣耀30。这就是bug出现的原因。

几乎所有的GPU,都可以支持fragment shader到mediump精度。除非你判断出某个GPU可以支持高精度,才改成highp。

2.2 解决

都捋清楚了,就好解决了。
把fragment shader加上一句:
precision mediump float;

完整的代码:

#version 300 es
precision mediump float;
in vec2 TexCoords;
out vec4 color;
uniform sampler2D text;
uniform vec3 textColor;
void main()
{
    
    
    vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);
    color = vec4(textColor, 1.0) * sampled;
}

3 参考

https://stackoverflow.com/questions/13780609/what-does-precision-mediump-float-mean
https://stackoverflow.com/questions/28540290/why-it-is-necessary-to-set-precision-for-the-fragment-shader
https://docs.unity3d.com/cn/current/Manual/SL-DataTypesAndPrecision.html

猜你喜欢

转载自blog.csdn.net/newchenxf/article/details/123373023