调用OpenGL函数时程序崩溃
Posted
技术标签:
【中文标题】调用OpenGL函数时程序崩溃【英文标题】:Program crash when calling OpenGL functions 【发布时间】:2016-11-05 18:13:06 【问题描述】:我正在尝试设置一个游戏引擎项目。我的视觉工作室项目已设置,因此我有一个与我的“游戏”项目分开的“引擎”项目。然后将引擎项目编译为 dll 供游戏项目使用。我已经下载并设置了 glfw 和 glew 以开始使用 openGL。我的问题是,当我遇到我的第一个 openGL 函数时,程序就会崩溃。我知道这与 glewinit 有关,即使 glew 初始化成功(没有控制台错误)。在我的引擎项目中,我有一个窗口类,在构建窗口时,应该设置 glew:
窗口.h
#pragma once
#include "GL\glew.h"
#include "GLFW\glfw3.h"
#if (_DEBUG)
#define LOG(x) printf(x)
#else
#define LOG(x)
#endif
namespace BlazeGraphics
class __declspec(dllexport) Window
public:
Window(short width, short height, const char* title);
~Window();
void Update();
void Clear() const;
bool Closed() const;
private:
int m_height;
int m_width;
const char* m_title;
GLFWwindow* m_window;
private:
Window(const Window& copy)
void operator=(const Window& copy)
;
Window.cpp(调用 glewinit() 的地方)
#include "Window.h"
#include <cstdio>
namespace BlazeGraphics
//Needed to define outside of the window class (not sure exactly why yet)
void WindowResize(GLFWwindow* window, int width, int height);
Window::Window(short width, short height, const char* title) :
m_width(width),
m_height(height),
m_title(title)
//InitializeWindow
if (!glfwInit())
LOG("Failed to initialize glfw!");
return;
;
m_window = glfwCreateWindow(m_width, m_height, m_title, NULL, NULL);
if (!m_window)
LOG("Failed to initialize glfw window!");
glfwTerminate();
return;
;
glfwMakeContextCurrent(m_window);
glfwSetWindowSizeCallback(m_window, WindowResize);
//IntializeGl
//This needs to be after two functions above (makecontextcurrent and setwindowresizecallback) or else glew will not initialize
**if (glewInit() != GLEW_OK)
LOG("Failed to initialize glew!");
**
Window::~Window()
glfwTerminate();
void Window::Update()
glfwPollEvents();
glfwSwapBuffers(m_window);
void Window::Clear() const
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//Returns a bool because glfwwindowShouldClose returns a nonzero number or zero
bool Window::Closed() const
//Made it equal to 1 to take away warning involving converting an int to bool
return glfwWindowShouldClose(m_window) == 1;
//Not part of window class so defined above
void WindowResize(GLFWwindow* window, int width, int height)
glViewport(0, 0, width, height);
这是我的 main.cpp 文件,该文件位于我的游戏项目中,我目前在全局函数中拥有我的 openGL 功能(暂时):
main.cpp
#include <iostream>
#include <array>
#include <fstream>
#include "GL\glew.h"
#include "GLFW\glfw3.h"
#include "../Engine/Source/Graphics/Window.h"
void initializeGLBuffers()
GLfloat triangle[] =
+0.0f, +0.1f, -0.0f,
0.0f, 1.0f, 0.0f,
-0.1f, -0.1f, 0.0f, //1
0.0f, 1.0f, 0.0f,
+0.1f, -0.1f, 0.0f, //2
0.0f, 1.0f, 0.0f,
;
GLuint bufferID;
glGenBuffers(1, &bufferID);
glBindBuffer(GL_ARRAY_BUFFER, bufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(triangle), triangle, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, (sizeof(GLfloat)) * 6, nullptr);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, (sizeof(GLfloat)) * 6, (char*)((sizeof(GLfloat)) * 3));
GLushort indices[] =
0,1,2
;
GLuint indexBufferID;
glGenBuffers(1, &indexBufferID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
;
void installShaders()
//Create Shader
GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
//Add source or text file to shader object
std::string temp = readShaderCode("VertexShaderCode.glsl");
const GLchar* adapter[1];
adapter[0] = temp.c_str();
glShaderSource(vertexShaderID, 1, adapter, 0);
temp = readShaderCode("FragmentShaderCode.glsl").c_str();
adapter[0] = temp.c_str();
glShaderSource(FragmentShaderID, 1, adapter, 0);
//Compile Shadaer
glCompileShader(vertexShaderID);
glCompileShader(FragmentShaderID);
if (!checkShaderStatus(vertexShaderID) || !checkShaderStatus(FragmentShaderID))
return;
//Create Program
GLuint programID = glCreateProgram();
glAttachShader(programID, vertexShaderID);
glAttachShader(programID, FragmentShaderID);
//Link Program
glLinkProgram(programID);
if (!checkProgramStatus(programID))
std::cout << "Failed to link program";
return;
//Use program
glUseProgram(programID);
int main()
BlazeGraphics::Window window(1280, 720, "MyGame");
initializeGLBuffers();
installShaders();
while (!window.Closed())
window.Clear();
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0);
window.Update();
;
return 0;
现在如果我将 glewinit() 代码移到我的 main.cpp 中:
int main()
BlazeGraphics::Window window(1280, 720, "MyGame");
if (glewInit() != GLEW_OK)
LOG("Failed to initialize glew!");
initializeGLBuffers();
installShaders();
while (!window.Closed())
window.Clear();
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0);
window.Update();
;
return 0;
然后我的程序编译得很好。为什么尝试在engine.dll 中初始化glew 会导致程序崩溃?感谢您的帮助。
【问题讨论】:
桌面。我不小心添加了 opengl-es 标签,现在删除它 只有当你的 OpenGL 上下文已经创建时,你才能调用glewInit
,否则你会碰壁...我没有看到任何 OpenGL 初始化...可能它隐藏在 BlazeGraphics::Window window(1280, 720, "MyGame");
中.此外,glewInit
和所有 OpenGL 的东西都应该从同一个线程中调用...
【参考方案1】:
GLEW 的工作原理是将函数指针定义为每个 OpenGL 函数的全局变量。我们以glBindBuffer
为例:
#define GLEW_FUN_EXPORT GLEWAPI
typedef void (GLAPIENTRY * PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
GLEW_FUN_EXPORT PFNGLBINDBUFFERPROC __glewBindBuffer;
所以我们只有一个__glewBindBuffer
函数指针,它将被glewInit
设置为您的OpenGL 实现中的正确地址。
为了真正能够编写glBindBuffer
,GLEW 只定义了将 GL 函数映射到这些函数指针变量的预处理器宏:
#define glBindBuffer GLEW_GET_FUN(__glewBindBuffer);
为什么尝试在
engine.dll
中初始化glew 会导致程序崩溃?
因为您的engine.dll
和您的主应用程序都有一组单独的所有这些全局变量。您必须从引擎 DLL 中导出所有 __glew*
变量,才能访问在 engine.dll
中调用 glewInit
的结果。
【讨论】:
感谢您的澄清。确保导出所有要在游戏项目中使用的 glew 变量的最佳方法是什么?动态链接 glew 而不是在引擎中静态链接它可以解决问题吗? @Jason:老实说:你可能不应该那样做,因为函数指针在上下文之间可能不同。从技术上讲,每次切换上下文时,您都必须调用glewInit
。正确的解决方案是拥有一个包含所有函数指针的结构或类,并通过它进行调用。然后,您可以在 DLL 之间传递指向该结构的指针。 – 当然,大多数 OpenGL 加载器的设计不允许它轻易做到这一点。我建议你在每个需要它的模块中调用glewInit
。
真的吗?那很有趣。我从没想过会是这样。感谢 datenwolf 的提醒以上是关于调用OpenGL函数时程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章