OpenGL:绑定统一缓冲区时出现异常
OpenGL: Exception when binding uniform buffer
我有以下 opengl 代码来绑定创建的缓冲区并用一些数据填充它。
#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;
}
输出是:
OpenGL Info:
Vendor: NVIDIA Corporation
Renderer: NVIDIA GeForce GTX 950/PCIe/SSE2
Version: 4.5.0 NVIDIA 466.27
12800
00000080860FE830
1
12800
而且我一直收到“在 main.exe 中的 0x0000000000000000 抛出的异常:0xC0000005:访问冲突执行位置 0x0000000000000000。”调用 glBufferSubData(GL_UNIFORM_BUFFER, 0, sl.size_bytes(), sl.data());
时
不太明白为什么?缓冲区似乎已绑定,我的输入数据不是 nullptr,并且大小匹配?任何帮助或调试建议表示赞赏。
为 64 位编译时在我的机器上得到了重现。没有在 32 位上崩溃,但我怀疑我只是幸运地访问了 sizes/layouts.
页
注意到这个:
constexpr size_t size_bytes() const noexcept
{
return size() * 2 * sizeof(glm::mat4);
^^^^ not a vec4?
}
更改 mat4
以匹配 Light
结构中的 vec4
解决了我这边的崩溃问题。
sizeof(lights)
或 size() * sizeof(Light)
也可以,如果 lights
的类型有可能在将来某个时候更改为动态容器,则优先选择后者。
一般来说,不要告诉 OpenGL 您要求它读取的内存缓冲区比实际长度要长。否则 OpenGL 会愉快地读取结束缓冲区,要么是抓取垃圾,要么是段错误。
我有以下 opengl 代码来绑定创建的缓冲区并用一些数据填充它。
#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;
}
输出是:
OpenGL Info:
Vendor: NVIDIA Corporation
Renderer: NVIDIA GeForce GTX 950/PCIe/SSE2
Version: 4.5.0 NVIDIA 466.27
12800
00000080860FE830
1
12800
而且我一直收到“在 main.exe 中的 0x0000000000000000 抛出的异常:0xC0000005:访问冲突执行位置 0x0000000000000000。”调用 glBufferSubData(GL_UNIFORM_BUFFER, 0, sl.size_bytes(), sl.data());
不太明白为什么?缓冲区似乎已绑定,我的输入数据不是 nullptr,并且大小匹配?任何帮助或调试建议表示赞赏。
为 64 位编译时在我的机器上得到了重现。没有在 32 位上崩溃,但我怀疑我只是幸运地访问了 sizes/layouts.
页注意到这个:
constexpr size_t size_bytes() const noexcept
{
return size() * 2 * sizeof(glm::mat4);
^^^^ not a vec4?
}
更改 mat4
以匹配 Light
结构中的 vec4
解决了我这边的崩溃问题。
sizeof(lights)
或 size() * sizeof(Light)
也可以,如果 lights
的类型有可能在将来某个时候更改为动态容器,则优先选择后者。
一般来说,不要告诉 OpenGL 您要求它读取的内存缓冲区比实际长度要长。否则 OpenGL 会愉快地读取结束缓冲区,要么是抓取垃圾,要么是段错误。