glCompileShader由于if语句而出现段错误

时间:2016-09-14 06:36:32

标签: c opengl segmentation-fault glsl shader

此片段着色器编译并正常工作:

#version 330 core
uniform sampler2D sampler;
uniform vec3 clr;
vec2 pos;
void main(void) {
    pos.x = gl_FragCoord.x / 960.0;
    pos.y = gl_FragCoord.y / 540.0;
    gl_FragColor = vec4(clr,1) * texture(sampler, pos.st);
}

这会在glCompileShader内的某处抛出分段错误:

#version 330 core
uniform sampler2D sampler;
uniform vec3 clr;
vec2 pos;
void main(void) {
    pos.x = gl_FragCoord.x / 960.0;
    pos.y = gl_FragCoord.y / 540.0;
    if (texture(sampler, pos.st).r > 0.5) {
        gl_FragColor = vec4(clr, 1) * 0.5;
    }
    else {
        gl_FragColor = vec4(clr, 1);
    }
}

其他一切都是一样的。有谁知道这背后的原因?

2 个答案:

答案 0 :(得分:1)

  

这会在glCompileShader

中的某处抛出分段错误

这些问题通常是由越界内存访问引起的。指定了glShaderSource的API(版本4.5)如下(我强调):

  

命令

void glShaderSource(
    GLuint shader,
    GLsizei count,
    const GLchar *const *string,
    const GLint *length );
     

将源代码加载到名为shader的着色器对象中。字符串是一个   指向可选空终止字符的计数指针数组   构成源代码的字符串。 长度参数是一个数组   每个字符串中的字符数(字符串长度)。如果   长度为负的元素,其伴随字符串为   空值终止。如果length为NULL,则为字符串参数中的所有字符串   被视为以空值终止。

这意味着如果你没有空终止你的着色器字符串,OpenGL希望你传递长度信息,反之亦然。

为什么这很重要?两个着色器源之间的一个重要区别是着色器源字符串的长度。并且很可能在较短的源结束后可能出现几个空字节¹。让着色器源字符串稍长一点的微小变化可能会对它在内存中的最终位置产生巨大影响。

那么为什么你的着色器源字符串不能以空值终止?例如,如果您从文件中读取它并将内存分配为文件大小。在这种情况下,不会有空终止字符。

要点是:要么正确地终止着色器源字符串,要么显式传入着色器源字符串长度。最好同时做两件事(对于超出范围的内存访问,它永远不会变得偏执)。

1:也许在之前的分配中遗留在同一个内存点,或者你的源字符串足够短,以至于它适合单个页面,而malloc实现决定请求一个新页面是合适的(通常是新页面)读取零,除非没有明确要求不初始化它们。)

答案 1 :(得分:0)

下面的代码应该可以正常工作。您的代码中的问题很棘手,因为它可能是优化期间的问题。

另外,是不是'texture2D'而不是'texture'?

#version 330 core
uniform sampler2D sampler;
uniform vec3 clr;
vec2 pos;
void main(void) {
    pos.x = gl_FragCoord.x / 960.0;
    pos.y = gl_FragCoord.y / 540.0;

    float rValue = texture(sampler, pos.st).r;

    gl_FragColor = vec4(clr, 1.0) * mix(1.0, 0.5, rValue > 0.5);
}