SDL_GL_SwapWindow触发访问违例错误,疑与EBO实现相关
Exception thrown at 0x00007FF9C6E74A40 (nvoglv64.dll) in SDL Julia Set Renderer.exe: 0xC0000005: Access violation reading location 0x0000000000000000.
尝试使用SDL与OpenGL渲染简单四边形,添加EBO(元素缓冲对象)代码后,程序在执行SDL_GL_SwapWindow(window)时触发上述访问违例错误,已更新NVIDIA显卡驱动但问题仍未解决,相关代码如下:
#include <SDL.h> #include <GL/glew.h> #include <SDL_opengl.h> #include <iostream> const int SCREEN_WIDTH = 640; const int SCREEN_HEIGHT = 480; int mouse_x, mouse_y; SDL_Window* window = NULL; SDL_Renderer* renderer = NULL; SDL_GLContext context = NULL; const char* vertexShaderSource = "#version 460\n" "layout(location = 0) in vec3 aPos;\n" "void main(){\n" " gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" "}\n"; const char* fragmentShaderSource = "#version 460\n" "out vec4 FragColor;\n" "void main(){\n" " FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" "}\n"; int main(int argv, char* argc[]) { SDL_Init(SDL_INIT_EVERYTHING); SDL_Init(SDL_VIDEO_OPENGL); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); window = SDL_CreateWindow("SDL Julia Set Renderer", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_OPENGL); context = SDL_GL_CreateContext(window); glewInit(); glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); unsigned int vertexShader; vertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); glCompileShader(vertexShader); int success; char infoLog[512]; glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; } unsigned int fragmentShader; fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); glCompileShader(fragmentShader); glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl; } unsigned int shaderProgram; shaderProgram = glCreateProgram(); glAttachShader(shaderProgram, vertexShader); glAttachShader(shaderProgram, fragmentShader); glLinkProgram(shaderProgram); glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog); std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; } glDeleteShader(vertexShader); glDeleteShader(fragmentShader); float verts[] = { -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f, 0.5f, 0.5f, 0.0f, -0.5f, 0.5f, 0.0f }; int indices[] = { 0, 1, 3, 1, 2, 3 }; unsigned int VBO, VAO, EBO; glGenVertexArrays(1, &VAO); glGenBuffers(1, &EBO); glGenBuffers(1, &VBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, EBO); glBufferData(GL_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, (void*)0); glEnableVertexAttribArray(0); bool isrunning = true; while (isrunning) { SDL_Event event; while (SDL_PollEvent(&event)) { if (event.type == SDL_QUIT) { isrunning = false; } } //Main Loop SDL_GetMouseState(&mouse_x, &mouse_y); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glUseProgram(shaderProgram); glBindVertexArray(VAO); //glDrawArrays(GL_TRIANGLES, 0, 3); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); /* Here's where the error took place */ SDL_GL_SwapWindow(window); } glDeleteVertexArrays(1, &VAO); glDeleteBuffers(1, &VBO); glDeleteProgram(shaderProgram); SDL_Quit(); return 0; }
问题根源与修复方案
代码存在三个关键问题,直接或间接导致了内存访问违例:
EBO绑定目标错误
EBO是元素缓冲对象,必须绑定到GL_ELEMENT_ARRAY_BUFFER目标,而非GL_ARRAY_BUFFER。当VAO处于绑定状态时,当前绑定的GL_ELEMENT_ARRAY_BUFFER会被VAO关联存储,后续调用glDrawElements时会自动使用这个EBO的索引数据。原代码用GL_ARRAY_BUFFER绑定EBO,VAO不会记录该缓冲,导致绘制时找不到有效索引数据,触发空指针访问。索引数据类型不匹配
原代码中索引数组indices定义为int类型,但glDrawElements指定的类型是GL_UNSIGNED_INT,类型不匹配会导致索引值被错误解析,进而引发内存访问异常。需将索引数组改为unsigned int类型。遗漏EBO资源释放
程序退出时未删除EBO,虽不直接导致当前错误,但属于资源泄漏问题,建议补上。
修正后的关键代码片段
1. 修正索引数组类型
unsigned int indices[] = { 0, 1, 3, 1, 2, 3 };
2. 修正EBO绑定与数据上传
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
3. 补充EBO资源释放
glDeleteVertexArrays(1, &VAO); glDeleteBuffers(1, &VBO); glDeleteBuffers(1, &EBO); // 新增删除EBO glDeleteProgram(shaderProgram);
内容的提问来源于stack exchange,提问作者Dreadward07

