glUniform4fv приводит к GL_INVALID_OPERATION - PullRequest
0 голосов
/ 23 октября 2019

Эй, у меня есть класс, абстрагирующий все связанное с шейдером, который называется Shader.cpp:

#include "Shader.h"
#include "Renderer.h"

#include <iostream>
#include <fstream>

Shader::Shader()
{
    GLCALL(m_RenderedID = glCreateProgram());
}


Shader::~Shader()
{
    GLCALL(glDeleteProgram(m_RenderedID));
}

void Shader::Bind() const
{
    GLCALL(glUseProgram(m_RenderedID));
}

void Shader::Unbind() const
{
    GLCALL(glUseProgram(0));
}

std::string ParseShader(const std::string& path)
{
    std::ifstream ifs(path);
    return std::string((std::istreambuf_iterator<char>(ifs)),
        (std::istreambuf_iterator<char>()));
}

static unsigned int CompileShader(unsigned int type, const std::string& source)
{
    GLCALL(unsigned int id = glCreateShader(type));
    const char* src = source.c_str();
    GLCALL(glShaderSource(id, 1, &src, nullptr));
    GLCALL(glCompileShader(id));

    int result;
    GLCALL(glGetShaderiv(id, GL_COMPILE_STATUS, &result));

    if (result == GL_FALSE)
    {
        int length;
        glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
        char* message = (char*)alloca(length * sizeof(char));
        GLCALL(glGetShaderInfoLog(id, length, &length, message));
        std::cout << "Failed to compile shader!" << std::endl;
        std::cout << message << std::endl;
        glDeleteShader(id);
        return 0;
    }
    return id;
}

void Shader::Attach(const unsigned int type, const std::string& path)
{
    unsigned int id = CompileShader(type, ParseShader(path));
    if (m_ShaderFiles.find(id) == m_ShaderFiles.end())
        m_ShaderFiles[id] = ShaderFile({ type, path });
    GLCALL(glAttachShader(m_RenderedID, id));
}

void Shader::Link()
{
    int result;

    GLCALL(glLinkProgram(m_RenderedID));
    GLCALL(glGetProgramiv(m_RenderedID, GL_LINK_STATUS, &result));

    if (result == GL_FALSE)
    {
        std::cout << "Failed to link shader!" << std::endl;
        return;
    }

    GLCALL(glValidateProgram(m_RenderedID));
    GLCALL(glGetProgramiv(m_RenderedID, GL_VALIDATE_STATUS, &result));

    if (result == GL_FALSE)
    {
        std::cout << "Failed to validate shader!" << std::endl;
        return;
    }

    for (const auto& shaderFile : m_ShaderFiles) {
        GLCALL(glDeleteShader(shaderFile.first));
    }
}

// this part is taken from Shader.h because it's templated
template<typename T, unsigned int S>
void SetUniform(Uniform<T, S>& uniform)
{
    Bind();
    uniform.Set(GetUniformLocation(uniform.GetName()));
}

int Shader::GetUniformLocation(const std::string& name)
{
    if (m_UniformLocationCache.find(name) != m_UniformLocationCache.end())
        return m_UniformLocationCache[name];

    GLCALL(int location = glGetUniformLocation(m_RenderedID, name.c_str()));
    m_UniformLocationCache[name] = location;
    return location;
}

Это мой app.cpp с использованием класса шейдеров:

#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include <iostream>
#include <fstream>
#include <string>

#include "core/renderer/Shader.h"
#include "core/renderer/uniform/Uniform4f.cpp"
#include "core/renderer/VertexArray.h"
#include "core/renderer/VertexBufferLayout.h"
#include "core/renderer/VertexBuffer.h"
#include "core/renderer/IndexBuffer.h"

int main(void)
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    glfwSwapInterval(1);

    if (glewInit() != GLEW_OK)
        std::cout << "Error!" << std::endl;

    std::cout << glGetString(GL_VERSION) << std::endl;

    float vertices[] = {
        -0.5f, -0.5f,
        0.5f, -0.5f,
        0.5f, 0.5f,
        -0.5f, 0.5f
    };

    unsigned int indices[] = {
        0, 1, 2,
        2, 3, 0
    };

    VertexArray va;
    VertexBufferLayout layout;
    layout.Push({ GL_FLOAT, 2, sizeof(float) * 2, GL_FALSE });

    VertexBuffer vb(vertices, sizeof(vertices), layout);

    IndexBuffer ib(indices, 6);

    va.AddVertexBuffer(vb);

    Shader shader;
    shader.Attach(GL_VERTEX_SHADER, "res/shaders/basic_vs.shader");
    shader.Attach(GL_FRAGMENT_SHADER, "res/shaders/basic_fs.shader");
    shader.Link();
    shader.Bind();

    Uniform4f colorUniform("u_Color");

    float r = 0.00f;
    float increment = 0.05f;
    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {
        /* Render here */
        glClear(GL_COLOR_BUFFER_BIT);

        colorUniform.SetValues({ r, 0.5f, 0.9f, 1.0f });
        shader.SetUniform(colorUniform);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);

        if (r > 1.0f)
            increment = -0.05f;
        else if (r < 0.0f)
            increment = 0.05f;

        r += increment;

        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}
#include <iostream>

Вот Uniform4f.cpp Я пытаюсь установить:

#include "Uniform.h"
#include "../Renderer.h"

#include <iostream>

class Uniform4f : public Uniform<float, 4>
{
public:
    Uniform4f(const std::string& name, const std::array<float, 4>& values = {})
        : Uniform(name, values)
    {

    }

    virtual void Set(int location)
    {
        GLCALL(glUniform4fv(location, m_Values.size(), reinterpret_cast<const GLfloat*>(m_Values.data())));
    }
};

Теперь я получаю GL_INVALID_OPERATION при вызове glUniform4fv(location, m_Values.size(), reinterpret_cast<const GLfloat*>(m_Values.data())) внутри вызова к shader.SetUniform(colorUniform); в цикле рендеринга в app.cpp.

docs утверждает, что это может быть одной из следующих проблем:

  • GL_INVALID_OPERATION генерируется, если нет текущего программного объекта.
  • GL_INVALID_OPERATION isгенерируется, если размер унифицированной переменной, объявленной в шейдере, не соответствует размеру, указанному командой glUniform.
  • GL_INVALID_OPERATION генерируется, если один из целочисленных вариантов со знаком или без знака этой функции используется для загрузки униформыпеременная типа float, vec2, vec3, vec4 или их массив, или если один из вариантов этой функции с плавающей запятой используется для загрузки единой переменной типа int, ivec2, ivec3, ivec4, unsigned int, uvec2, uvec3, uvec4 или их массив.
  • GL_INVALID_OPERATION генерируется, если один из целочисленных вариантов этой функции со знаком используется для загрузки универсальной переменной типа unsigned int, uvec2, uvec3, uvec4 илиих массив.
  • GL_INVALID_OPERATION генерируется, если один из целочисленных вариантов без знака этой функции используется для загрузки универсальной переменной типа int, ivec2, ivec3, ivec4 или их массива.
  • GL_INVALID_OPERATION генерируется, если location является недопустимым единообразным местоположением для текущего программного объекта, и местоположение не равно -1.
  • GL_INVALID_OPERATION генерируется, если count больше 1 и указанная универсальная переменная не являетсяпеременная массива.
  • GL_INVALID_OPERATION генерируется, если сэмплер загружается с использованием команды, отличной от glUniform1i и glUniform1iv.

Я не могу понять, какая ошибка может вызвать это, кромевыше кажется правильным. Во время отладки я вижу, что унифицированные значения, размер и местоположение, которые передаются в glUniform4fv, являются правильными, мои шейдерные программы в Bind редактируются после Link в app.cpp, так что я неконечно, что вызвало это.

Я был бы благодарен за помощь в этом.

1 Ответ

1 голос
/ 23 октября 2019

Хорошо, я понял это. В docs скажем:

count
Для команд вектора (glUniform * v) указывается количество элементов, которые должны быть изменены. Это должно быть 1, если целевая универсальная переменная не является массивом, и 1 или более, если это массив.

Это немного сбивает с толку, но моя ошибка в том, что target униформапеременная только 1 vec4, а не массив vec4, и это то, что представляет count.

...