Home > Net >  GLSL program fails to link depending on their files' size
GLSL program fails to link depending on their files' size

Time:09-16

I've a weird problem with GLSL shaders. My program seems to not launch or launch successfully depending on the size of my shader files. If I only write a few lines of code in shader files, the program works fine. For example, the program launches successfully with this much code:

vertex.vs:

#version 460 core

layout (location = 0) in vec2 coords;

uniform float u_time;

out vec3 result_color;

void main()
{
    vec3 colorA = vec3(0.514f, 0.179f, 0.900f);
    vec3 colorB = vec3(0.895f, 0.359f, 0.488f);

    gl_Position = vec4(coords, 0.0f, 1.0f);
    result_color = colorA;
}

fragment.fs:

#version 460 core

in vec3 result_color;

out vec4 color;

void main() 
{    
    color = vec4(result_color, 1.0f);
}

If I add more code to any of my shader files it only launches about 50% of the time:

vertex.vs:

#version 460 core

layout (location = 0) in vec2 coords;

uniform float u_time;

out vec3 result_color;

// float wave(float x)
// {
//     return min(2.0f - 2.0f * fract(x / 2.0f), 
//                2.0f * fract(x / 2.0f));
// }

void main()
{
    vec3 colorA = vec3(0.514f, 0.179f, 0.900f);
    vec3 colorB = vec3(0.895f, 0.359f, 0.488f);

    // float frequency = 15.0f;
    // float y = wave(coords.x * frequency   cos(u_time) * 5.0f);
    // float fr_y = fract(coords.y * frequency   u_time);
    
    gl_Position = vec4(coords, 0.0f, 1.0f);
    result_color = colorA;
}

Note that the code I added is commented out but still the error occurs. And the more code I add the less is the chance it works. Here's the class I use to read shaders from files and create a shader program:

#include <iostream>
#include <fstream>
#include <sstream>

#include <glad/glad.h>

#include "shader_program.h"

ShaderProgram::ShaderProgram(std::string vertexShaderPath, std::string fragmentShaderPath)
{
    std::ifstream vShaderFile;
    std::ifstream fShaderFile;
    std::stringstream vShaderStream;
    std::stringstream fShaderStream;

    vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
    fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);

    try 
    {
        vShaderFile.open(vertexShaderPath);
        vShaderStream << vShaderFile.rdbuf();
    }
    catch(std::ifstream::failure e)
    {
        std::cout << "ERROR: FAILED TO READ SHADER FILE: VERTEX SHADER" << std::endl;
    }

    try 
    {
        fShaderFile.open(fragmentShaderPath);
        fShaderStream << fShaderFile.rdbuf();
    }
    catch(std::ifstream::failure e)
    {
        std::cout << "ERROR: FAILED TO READ SHADER FILE: FRAGMENT SHADER" << std::endl;
    }

    const char* vertexShaderSource = vShaderStream.str().c_str();
    const char* fragmentShaderSource = fShaderStream.str().c_str();

    CreateShaderProgram(vertexShaderSource, fragmentShaderSource);
}

unsigned int ShaderProgram::GetProgram()
{
    return program;
}

void ShaderProgram::CreateShaderProgram(const char* vertexShaderSource, const char* fragmentShaderSource)
{
    program = glCreateProgram();
    unsigned int vertexShader = CompileShader(GL_VERTEX_SHADER, vertexShaderSource);
    unsigned int fragmentShader = CompileShader(GL_FRAGMENT_SHADER, fragmentShaderSource);

    glAttachShader(program, vertexShader);
    glAttachShader(program, fragmentShader);
    glLinkProgram(program);

    int linkingResult;
    glGetProgramiv(program, GL_LINK_STATUS, &linkingResult);
    if (linkingResult == GL_FALSE)
    {
        char infoLog[512];
        glGetProgramInfoLog(program, 512, NULL, infoLog);
        std::cout << "ERROR: FAILED TO LINK PROGRAM\n" << infoLog << std::endl;
    }
}

unsigned int ShaderProgram::CompileShader(GLuint type, const char* source)
{
    unsigned int shader = glCreateShader(type);
    glShaderSource(shader, 1, &source, NULL);
    glCompileShader(shader);

    int compilationResult;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &compilationResult);
    if (compilationResult == GL_FALSE)
    {
        char infoLog[512];
        glGetShaderInfoLog(shader, 512, NULL, infoLog);

        std::cout << "ERROR: FAILED TO COMPILE SHADER: " 
                  << (type == GL_VERTEX_SHADER ? "VERTEX" : "FRAGMENT") 
                  << " SHADER\n" << infoLog << std::endl;
    }

    return shader;
}

The error message I get sometimes seems random. Most of the time it's this:

ERROR: FAILED TO LINK PROGRAM
Vertex shader(s) failed to link, fragment shader(s) failed to link.
Vertex link error: INVALID_OPERATION.
ERROR: error(#97) No program main found
fragment link error: INVALID_OPERATION.
ERROR: error(#97) No program main found

But sometimes it's about a syntax error which is nowhere to be found really:

ERROR: FAILED TO COMPILE SHADER: VERTEX SHADER
Vertex shader failed to compile with the following errors:
ERROR: 0:1: error(#132) Syntax error: "0" parse error
ERROR: error(#273) 1 compilation errors.  No code generated


ERROR: FAILED TO LINK PROGRAM
Vertex shader(s) were not successfully compiled before glLinkProgram() was called.  Link failed.

I use GLFW 3.3.8 and Glad. I started with OpenGL version 3.3 and tried switching to 4.6 which had no effect. Also tried to update my GPU drivers to no success either. I really have no idea where this behaviour may be coming from.

CodePudding user response:

You have undefined behaviour.

vShaderStream.str().c_str();

str() returns string by value. So this temporary string object is destroyed at the end of full expression, and the pointer obtained by c_str() is dangling. As a solution you could do:

CreateShaderProgram(vShaderStream.str().c_str(), fShaderStream.str().c_str());

in case above, string temporaries are still alive when CreateShaderProgram is called.

  •  Tags:  
  • c
  • Related