Jorayen
Jorayen

Reputation: 1971

glUniform4fv results in GL_INVALID_OPERATION

Hey I have a class abstracting everything shader related called 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;
}

This is my app.cpp using the Shader class:

#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>

Here's the Uniform4f.cpp I'm trying to set:

#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())));
    }
};

Now I'm getting GL_INVALID_OPERATION on the call to glUniform4fv(location, m_Values.size(), reinterpret_cast<const GLfloat*>(m_Values.data())) inside the call to shader.SetUniform(colorUniform); in the render loop in app.cpp.

The docs states it can either be one of these problems:

I can't really figure which error could cause it, non of the above seems right. While debugging I see that the uniform values, size, and location that are passed to glUniform4fv are all correct, my shader programs in Binded after it was Linked in the app.cpp, so I'm not sure what's causing this.

I would be thankful to get any help on this.

Upvotes: 0

Views: 1126

Answers (1)

Jorayen
Jorayen

Reputation: 1971

Ok I figured it out. The docs say:

count
For the vector (glUniform*v) commands, specifies the number of elements that are to be modified. This should be 1 if the targeted uniform variable is not an array, and 1 or more if it is an array.

It's kind confusing but my mistake is that the target uniform variable is only 1 vec4 and not an array of vec4 and that's what count represent.

Upvotes: 1

Related Questions