我应该仅在附加着色器并链接后检查编译错误吗?

问题描述 投票:0回答:1

当我以相反的方式执行此操作时,会出现编译错误,该错误本质上是空的,并出现一些奇怪的字符。 它在一个类中,所以我不知道需要查看代码的哪一部分。 但编译着色器后,我在构造函数中执行此操作

glAttachShader(m_ID, vertexShader);
glAttachShader(m_ID, fragmentShader);
glLinkProgram(m_ID);
checkForErrors(vertexShader, fragmentShader);

这有效,但是这个:

glAttachShader(m_ID, vertexShader);
glAttachShader(m_ID, fragmentShader);
checkForErrors(vertexShader, fragmentShader);
glLinkProgram(m_ID);

(请注意,现在在 glLinkProgram 之前调用 checkForErrors)这不起作用...... 这很奇怪,因为当单步执行程序时 我用

glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
我看到调用此函数后 length 的值为零 但是
glGetShaderiv(shader, GL_COMPILE_STATUS, &res);
将 res 设置为 0 表示错误... 然后,即使没有使用 _malloca 作为 infoLog 数组,而是在堆栈上分配了固定大小(例如 500),那么我会得到一个更长的字符串,但又充满了奇怪的字符...

无论如何,checkForErrors函数是重载的,所以它是这样的:

{
    checkForErrors(ShaderType::vertex, vertexShader);
    checkForErrors(ShaderType::fragment, fragmentShader);
    //checkForErrors(ShaderType::program, m_ID);
}

我注释掉了最后一部分,因为我试图强制链接错误并看看是什么

glValidateProgram(m_ID);
会做。所以这是最有可能发生错误的函数:

***由于我最终对其进行了一些更改,更新后的版本如下:

void Shader::checkForErrors(ShaderType type, U32 shader)
{
    const char* typeStr{ getTypeStr(type) };
    int length, res;
    if (type != ShaderType::program)
    {
        glGetShaderiv(shader, GL_COMPILE_STATUS, &res);
        if (!res)
        {
            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
            //char* infoLog{ (char*)_malloca(length) };
            char infoLog[500];
            glGetShaderInfoLog(shader, length, &length, infoLog);
            std::cout << typeStr << " shader failed to compile:\n" << infoLog << '\n';
            std::abort();
        }
    }
    else
    {
        glGetProgramiv(shader, GL_LINK_STATUS, &res);
        if (!res)
        {
            glGetProgramiv(shader, GL_INFO_LOG_LENGTH, &length);
            //char* infoLog((char*)_malloca(length));
            char infoLog[500];
            glGetProgramInfoLog(shader, length, &length, infoLog);
            std::cout << typeStr << " shader failed to link:\n" << infoLog << '\n';
            std::abort();
        }
    }
}

但是之前的问题仍然存在,只是首先我们看到有一个编译错误,然后在 if 块内我们得到它的长度为 0,然后当然我得到了这些奇怪的字符,因为没有任何东西可以写入 infoLog ... 这就是我之前的情况,为了让我所说的有意义,我将保留这一点。 也许我应该删除上面的内容并重新编写它,但它的行为几乎相同,并且看起来比旧版本有一个小变化,自从那件事发生以来,我认为我还应该包括:

void Shader::checkForErrors(ShaderType type, U32 shader)
{
    const char* typeStr{ getTypeStr(type) };
    int length, res;
    if (type != ShaderType::program)
    {
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);

        //char* infoLog{ (char*)_malloca(length) };
        char infoLog[500];
        glGetShaderiv(shader, GL_COMPILE_STATUS, &res);
        if (!res)
        {
            glGetShaderInfoLog(shader, length, &length, infoLog);
            std::cout << typeStr << " shader failed to compile:\n" << infoLog << '\n';
            std::abort();
        }
    }
    else
    {
        glGetProgramiv(shader, GL_INFO_LOG_LENGTH, &length);
        char* infoLog((char*)_malloca(length));
        glGetProgramiv(shader, GL_LINK_STATUS, &res);
        if (!res)
        {
            glGetProgramInfoLog(shader, length, &length, infoLog);
            std::cout << typeStr << " shader failed to link:\n" << infoLog << '\n';
            std::abort();
        }
    }
}

typeStr 只是根据类型的顶点、片段或程序,它只是一个无符号整数枚举。

后来写完后,我意识到最好移动 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);和 if(!res) 块内的 infoLog 但即便如此,即使不使用 _malloca 我也会得到相同的错误,这只是奇怪的字符而不是解释错误......但是如果我重新排序它,它会再次起作用并且我得到一个三角形屏幕上...

所以我想知道我搞砸了什么...... 这是我尝试过的: 我没有通过 const 引用获取 stringstream 中的字符串,而是将它们复制到 const std::string ,但这没有效果(请参见下面的 Shader 构造函数) 我什至尝试使用 int 枚举,所以它也不是这样的(在下面的 Shader.h 中) 不使用 _malloca 没有任何效果,可以通过函数的“更新”版本看到小的重新排序,在附加着色器之前移动 checkForErrors,使用 int 枚举而不是 U32(无符号整数)。通过谷歌搜索并故意破坏顶点着色器并破坏顶点着色器,同时保留导致错误的“错误”顺序,确保发生错误时 res 应该为 0。 我仍然收到奇怪的错误,而不是应该告诉我有关顶点着色器的错误。如果我需要首先链接程序,然后检查着色器中的编译错误,所有这些都是有意义的,但我想我记得过去做了完全相同的想法...... 无论如何,我想我错了?那么如何故意造成链接错误呢? 我尝试删除 glLinkProgram,但没有出现链接错误,而是出现了这个奇怪的错误。

因此,为了以防万一需要整个类,这里是它的 cpp 文件:

#include "Shader.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include "ASSERT.h"
Shader::Shader(const char* vertexPath, const char* fragmentPath)
    : m_ID{ glCreateProgram() }
{
    std::ifstream vertex{ vertexPath };
    std::ifstream fragment{ fragmentPath };
    std::stringstream vertexStream;
    std::stringstream fragmentStream;

    ASSERT(vertex, "Couldn't open vertexShader file");
    ASSERT(fragment, "Couldn't open fragmentShader file");

    vertexStream << vertex.rdbuf();
    fragmentStream << fragment.rdbuf();

    //std::cout << "\nVertex shader:\n" << vertexStream.str() << "\n\n\n"
    //  << "Fragment shader:\n" << fragmentStream.str() << "\n\n\n";

    /*const std::string& vertexStr{ vertexStream.str() };
    const std::string& fragmentStr{ fragmentStream.str() };*/

    const std::string& vertexStr{ vertexStream.str() };
    const std::string& fragmentStr{ fragmentStream.str() };
    const char* vSrc{ vertexStr.c_str()};
    const char* fSrc{ fragmentStr.c_str()};

    U32 vertexShader = compile(ShaderType::vertex, vSrc);
    U32 fragmentShader = compile(ShaderType::fragment, fSrc);

    glAttachShader(m_ID, vertexShader);
    glAttachShader(m_ID, fragmentShader);
    checkForErrors(vertexShader, fragmentShader);
    //glLinkProgram(m_ID);
    //glValidateProgram(m_ID);
    
}

void Shader::checkForErrors(U32 vertexShader, U32 fragmentShader)
{
    checkForErrors(ShaderType::vertex, vertexShader);
    checkForErrors(ShaderType::fragment, fragmentShader);
    //checkForErrors(ShaderType::program, m_ID);
}

U32 Shader::compile(ShaderType type, const char* source)
{
    U32 shader = glCreateShader(int(type));
    glShaderSource(shader, 1, &source, nullptr);
    glCompileShader((int)type);
    //glAttachShader(m_ID, shader);
    return shader;
}

const char* Shader::getTypeStr(ShaderType type)
{
    switch (type)
    {
    case ShaderType::program: return "program"; 
    case ShaderType::vertex: return "vertex"; 
    case ShaderType::fragment: return "fragment"; 
    default:
        ASSERT(false, "ShaderType enum of unknown type, should be program, vertex or fragment");
        return "noShader";
    }
    //return "noShader";
}

void Shader::checkForErrors(ShaderType type, U32 shader)
{
    const char* typeStr{ getTypeStr(type) };
    int length, res;
    if (type != ShaderType::program)
    {
        glGetShaderiv(shader, GL_COMPILE_STATUS, &res);
        if (!res)
        {
            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
            //char* infoLog{ (char*)_malloca(length) };
            char infoLog[500];
            glGetShaderInfoLog(shader, length, &length, infoLog);
            std::cout << typeStr << " shader failed to compile:\n" << infoLog << '\n';
            std::abort();
        }
    }
    else
    {
        glGetProgramiv(shader, GL_LINK_STATUS, &res);
        if (!res)
        {
            glGetProgramiv(shader, GL_INFO_LOG_LENGTH, &length);
            //char* infoLog((char*)_malloca(length));
            char infoLog[500];
            glGetProgramInfoLog(shader, length, &length, infoLog);
            std::cout << typeStr << " shader failed to link:\n" << infoLog << '\n';
            std::abort();
        }
    }
}

void Shader::bind()
{
    glUseProgram(m_ID);
}

void Shader::unBind()
{
    glUseProgram(0);
}

void Shader::Delete(U32 vs, U32 fs)
{
    glDeleteShader(vs);
    glDeleteShader(fs);
}
c++ opengl glsl
1个回答
0
投票

GL_INFO_LOG_LENGTH

信息日志的长度,包括空值 终止符,返回。如果信息日志为空,则返回零。

glGetShaderInfoLog

可以写入 infoLog 的最大字符数(包括空终止符)由 bufSize 指定。

结论:

如果

GL_INFO_LOG_LENGTH

返回零长度,并且该值被指定为

glGetShaderInfoLog
的最大长度,那么(至少根据我的理解)不会(可以)将任何内容写入指定的缓冲区,因此是垃圾(未初始化的字符数组)将被发送到输出。
对于长度为 

0

的情况,如果执行以下操作:

glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
if (length) {
    const GLint max_length = 500;
    char infoLog[max_length];
    glGetShaderInfoLog(shader, max_length, nullptr, infoLog);
    std::cout << "info log: " << infoLog << '\n';
} else {
    std::cout << "no info log available\n";
}

参考资料:

    https://registry.khronos.org/OpenGL-Refpages/gl4/html/glGetShader.xhtml
  • https://registry.khronos.org/OpenGL-Refpages/gl4/html/glGetShaderInfoLog.xhtml
  • OpenGL 规范 4.6 核心配置文件(第 7.14 章)-
  • https://registry.khronos.org/OpenGL/specs/gl/glspec46.core.pdf
© www.soinside.com 2019 - 2024. All rights reserved.