在着色器程序中重新编译,重新链接顶点着色器

Recompile, relink, vertex shader in shader program

本文关键字:链接 顶点 新链接 新编译 程序 编译      更新时间:2023-10-16

我有一个系统来检测对我的着色器文件所做的更改。当着色器发生变化时,假设是顶点着色器,我想编译那个着色器并用旧版本替换它(而不是改变着色器的输入/输出,从而重用VAO, VBO等)。

std::pair<bool, std::string> Shader::recompile() {
std::string vertex_src = load_shader_source(vertex_filepath);
glDetachShader(gl_program, vertex_shader); // gl_program is a GLuint for the shader program
glDeleteShader(vertex_shader);
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
auto raw_str = vertex_src.c_str();
glShaderSource(vertex_shader, 1, &raw_str, NULL);
glCompileShader(vertex_shader);
GLint vertex_shader_status;
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &vertex_shader_status);
GLint fragment_shader_status = 1;
if (vertex_shader_status == 1) {
    glAttachShader(gl_program, vertex_shader);
    // glLinkProgram(gl_program);
    // Logging - mostly irrelevant to the question
    GLint is_linked = 0;
    glGetProgramiv(gl_program, GL_LINK_STATUS, &is_linked);
    SDL_Log("Shader relinking is success: %i", is_linked == GL_TRUE);
    std::string err_log = "";
    GLint max_log_lng = 0;
    glGetProgramiv(gl_program, GL_INFO_LOG_LENGTH, &max_log_lng);
    err_log.reserve(max_log_lng);
    glGetProgramInfoLog(gl_program, max_log_lng, NULL, (char *) err_log.c_str());
    SDL_Log("%s", err_log.c_str());
    return {true, ""};
}

使用这种方法的结果是什么都没有改变,但是当我链接程序(在if语句中)时,它就消失了。我认为这是因为链接改变了所有的绑定,从而使现有的绑定无效,导致根本没有呈现任何内容。

那么,在着色器程序中像这样热换特定的着色器是可能的吗?

链接不会使任何属性绑定失效,因为它们是VAO状态的一部分,而不是程序的一部分。当重新链接程序时,有两种情况可能发生:

  • 属性的索引可能会改变。这可以通过在两个着色器(layout (location=...))中修复它们或在编译和加载(glBindAttribLocation​)之间修复它们来防止。同样的事情也可能发生在制服上,可以用同样的方式处理。
  • 制服值丢失。这不能简单地阻止,但在每帧中设置它们应该解决这个问题。