OpenGL: Exception when binding uniform buffer

1

I have the following opengl code to bind a created buffer and fill it with some data.

#include <glad/glad.h> 
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <array>
#include <iostream>

template <size_t max_lights = 100>
class SceneLights
{
private:
    struct Light
    {
        glm::vec4 position;
        glm::vec4 color;
    };

    std::array<Light, max_lights> lights;

public:
    SceneLights()
    {
        lights.fill(Light(glm::vec4(0.0), glm::vec4(0.0)));
    }

    constexpr size_t size() const noexcept
    {
        return lights.size();
    }

    constexpr size_t size_bytes() const noexcept
    {
        return size() * 2 * sizeof(glm::mat4);
    }

    constexpr Light const* data() const noexcept
    {
        return lights.data();
    }
};

int main()
{
    GLFWwindow* window;

    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);

    window = glfwCreateWindow(800, 600, "The Window", NULL, NULL);
    if (window == nullptr)
    {
        glfwTerminate();
        throw "Failed to create GLFW window";
    }

    glfwMakeContextCurrent(window);
    glfwSwapInterval(0);

    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        throw "Failed to initialize GLAD";
    }

    std::cout << "OpenGL Info:" << std::endl;
    std::cout << "  Vendor: " << glGetString(GL_VENDOR) << std::endl;
    std::cout << "  Renderer: " << glGetString(GL_RENDERER) << std::endl;
    std::cout << "  Version: " << glGetString(GL_VERSION) << std::endl;

    SceneLights sl = SceneLights();

    unsigned int ubo_id;

    glGenBuffers(1, &ubo_id);

    glBindBuffer(GL_UNIFORM_BUFFER, ubo_id);
    glBufferData(GL_UNIFORM_BUFFER, sl.size_bytes(), NULL, GL_DYNAMIC_DRAW);
    glBindBuffer(GL_UNIFORM_BUFFER, 0);

    glBindBufferRange(GL_UNIFORM_BUFFER, 0, ubo_id, 0, sl.size_bytes());

    glBindBuffer(GL_UNIFORM_BUFFER, ubo_id);
    int buf;
    int size;
    glGetIntegerv(GL_UNIFORM_BUFFER_BINDING, &buf);
    glGetBufferParameteriv(GL_UNIFORM_BUFFER, GL_BUFFER_SIZE, &size);
    std::cout << sl.size_bytes() << std::endl;
    std::cout << sl.data() << std::endl;
    std::cout << buf << std::endl;
    std::cout << size << std::endl;
    glBufferSubData(GL_UNIFORM_BUFFER, 0, sl.size_bytes(), sl.data());

    return 0;
}

the output is:

OpenGL Info:
  Vendor: NVIDIA Corporation
  Renderer: NVIDIA GeForce GTX 950/PCIe/SSE2
  Version: 4.5.0 NVIDIA 466.27
12800
00000080860FE830
1
12800

And I am consistently getting "Exception thrown at 0x0000000000000000 in main.exe: 0xC0000005: Access violation executing location 0x0000000000000000." when calling glBufferSubData(GL_UNIFORM_BUFFER, 0, sl.size_bytes(), sl.data());

I don't quite understand why? The buffer seems to be bound, my input data isn't a nullptr, and the sizes match up? Any help or debugging suggestions appreciated.

c++
visual-studio
visual-c++
glm-math
asked on Stack Overflow May 13, 2021 by Cascades • edited May 14, 2021 by Rabbid76

1 Answer

1

Got repro on my machine when compiling for 64-bit. Didn't crash on 32-bit but I suspect I just got lucky with page sizes/layouts.

Noticed this:

constexpr size_t size_bytes() const noexcept
{
    return size() * 2 * sizeof(glm::mat4);
                                    ^^^^ not a vec4?
}

Changing the mat4 to match the vec4s in the Light struct fixed the crash on my end.

sizeof(lights) or size() * sizeof(Light) also work, with a preference for the latter if there's any chance the type of lights is expected to change to a dynamic container sometime in the future.

In general, don't tell OpenGL that memory buffers you ask it to read from are longer than they actually are. Otherwise OpenGL will happily read off the end buffer, either grabbing garbage or a segfault.

answered on Stack Overflow May 13, 2021 by genpfault

User contributions licensed under CC BY-SA 3.0