添加额外的渲染调用时,GLFW 挂起关闭
Posted
技术标签:
【中文标题】添加额外的渲染调用时,GLFW 挂起关闭【英文标题】:GLFW hangs on close when adding an extra rendering call 【发布时间】:2014-12-12 15:34:03 【问题描述】:因此,在过去的一段时间里,我一直在尝试学习如何编写 openGL,尽管它在很多时候都令人费解,但我认为我开始对它的工作原理有了深入的了解。
我一直在使用 GLFW 进行窗口处理和基本输入,并使用 GLEW 访问扩展方法。
我也一直在关注www.learnopengl.com 上的教程,这非常有用。不过,最近,我一直在花一些时间尝试创建一些基本的抽象,以便在屏幕上绘图。当我抽象出教程提供的一些代码时,一切都很好(我仍在“入门”的坐标系部分)。
这样做之后,我决定模拟一个简单的 UI 叠加层会很好,我只有一个函数可以在 2-D 而不是 3-D 的屏幕上绘制一个矩形,并且只是浮动在屏幕上的其他所有内容之上.最终,我为 UI 和 3-D 对象使用了不同的着色器。它成功地在屏幕上绘制了一个彩色矩形,但不幸的是,我遇到了一个奇怪的问题,即每当我尝试通过将 glfwSetWindowShouldClose 调用设置为 true 来关闭窗口时,窗口可能会无限期挂起。
每当我删除绘制简单二维矩形的调用时,此挂起就会消失,并且窗口会立即按预期关闭。有谁知道为什么会这样?
Main.cpp
// GLEW
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h>
// GL includes
#include "shader.h"
// GLM Mathemtics
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
// Other Libs
#include <SOIL.h>
#include "glfw_x360_button_mappings.h"
#include "cube.h"
#include "texture.h"
// Function prototypes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
void handleControllerInput(GLFWwindow* window);
// GLOBALS!!!
const unsigned int MONITOR_WIDTH = 1920;
const unsigned int MONITOR_HEIGHT = 1080;
const unsigned int SCREEN_WIDTH = 800;
const unsigned int SCREEN_HEIGHT = 600;
float camera_z = -3.0f;
float camera_x = 0.0f;
// The MAIN function, from here we start our application and run our Game loop
int main()
// Init GLFW
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "LearnOpenGL", nullptr, nullptr); // Windowed
// TODO: Make window position adapt to any sized window.
glfwSetWindowPos(window, (MONITOR_WIDTH / 2) - (SCREEN_WIDTH / 2), (MONITOR_HEIGHT / 2) - (SCREEN_HEIGHT / 2));
glfwMakeContextCurrent(window);
// Set the required callback functions
glfwSetKeyCallback(window, key_callback);
// Initialize GLEW to setup the OpenGL Function pointers
glewExperimental = GL_TRUE;
glewInit();
// Define the viewport dimensions
glViewport(0, 0, 800, 600);
// Setup OpenGL options
glEnable(GL_DEPTH_TEST);
// Setup and compile our shaders
GLuint vert_id = buildShader("shader.vert", GL_VERTEX_SHADER);
GLuint frag_id = buildShader("shader.frag", GL_FRAGMENT_SHADER);
GLuint shader_program_id = buildProgram(vert_id, frag_id);
glDeleteShader(vert_id);
glDeleteShader(frag_id);
vert_id = buildShader("shader_ui.vert", GL_VERTEX_SHADER);
frag_id = buildShader("shader_ui.frag", GL_FRAGMENT_SHADER);
GLuint ui_shader_program_id = buildProgram(vert_id, frag_id);
glDeleteShader(vert_id);
glDeleteShader(frag_id);
// World space positions of our cubes
glm::vec3 cubePositions[] =
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(2.0f, 5.0f, -15.0f),
glm::vec3(-1.5f, -2.2f, -2.5f),
glm::vec3(-3.8f, -2.0f, -12.3f),
glm::vec3(2.4f, -0.4f, -3.5f),
glm::vec3(-1.7f, 3.0f, -7.5f),
glm::vec3(1.3f, -2.0f, -2.5f),
glm::vec3(1.5f, 2.0f, -2.5f),
glm::vec3(1.5f, 0.2f, -1.5f),
glm::vec3(-1.3f, 1.0f, -1.5f)
;
// Load and create a texture
GLuint texture1 = create_texture("container.jpg");
GLuint texture2 = create_texture("awesomeface.png");
glm::mat4 view_matrix;
glm::mat4 view_matrix_origin;
glm::mat4 projection_matrix;
view_matrix_origin = glm::translate(view_matrix, glm::vec3(0.0f, 0.0f, 0.0f));
projection_matrix = glm::perspective(45.0f, (float) 512 / (float) 512, 0.1f, 1000.0f);
GLint view_matrix_location = glGetUniformLocation(shader_program_id, "view");
GLint projection_matrix_location = glGetUniformLocation(shader_program_id, "projection");
glUseProgram(shader_program_id);
glUniformMatrix4fv(projection_matrix_location, 1, GL_FALSE, glm::value_ptr(projection_matrix));
Cube test_cube;
init_cube(&test_cube, cube_vertices, sizeof(cube_vertices));
// Game loop
while(!glfwWindowShouldClose(window))
// Check and call events
glfwPollEvents();
handleControllerInput(window);
// Clear the colorbuffer
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shader_program_id);
// Bind Textures using texture units
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glUniform1i(glGetUniformLocation(shader_program_id, "ourTexture1"), 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
glUniform1i(glGetUniformLocation(shader_program_id, "ourTexture2"), 1);
glUniform1f(glGetUniformLocation(shader_program_id, "time"), glfwGetTime());
view_matrix = glm::translate(view_matrix_origin, glm::vec3(camera_x, 0.0f, camera_z));
glUniformMatrix4fv(view_matrix_location, 1, GL_FALSE, glm::value_ptr(view_matrix));
/* THIS IS THE OFFENDING DRAW CALL
* IF REMOVED THE WINDOW STOPS HANGING ON CLOSE */
draw_rect(ui_shader_program_id, glm::vec2(0.0f, 0.0f));
for (GLuint i = 0; i < 10; i++)
GLfloat angle = glfwGetTime() * 25.0f;
draw_cube(&test_cube, shader_program_id, cubePositions[i], angle);
// Swap the buffers
glfwSwapBuffers(window);
glfwTerminate();
return 0;
// Is called whenever a key is pressed/released via GLFW
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
std::cout << key << std::endl;
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
void handleControllerInput(GLFWwindow* window)
if (glfwJoystickPresent(GLFW_JOYSTICK_1))
int size;
const unsigned char* results = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &size);
if (get_current_button_pressed(results, size) == X360_DPAD_DOWN)
camera_z += 0.001f;
else if (get_current_button_pressed(results, size) == X360_DPAD_UP)
camera_z -= 0.001f;
if (get_current_button_pressed(results, size) == X360_DPAD_LEFT)
camera_x -= 0.001f;
else if (get_current_button_pressed(results, size) == X360_DPAD_RIGHT)
camera_x += 0.001f;
if (get_current_button_pressed(results, size) == X360_B_BUTTON)
camera_z = -3.0f;
camera_x = 0.0f;
if (get_current_button_pressed(results, size) == X360_BACK_BUTTON)
glfwSetWindowShouldClose(window, true);
rect.h
#ifndef RECT_H
#define RECT_H
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
const GLfloat rect_vertices[] =
0.75f, 0.5f, 1.0f, 0.7f, 0.0f,
0.75f, -0.5f, 1.0f, 0.7f, 0.0f,
-0.75f, 0.5f, 1.0f, 0.7f, 0.0f,
-0.75f, 0.5f, 1.0f, 0.7f, 0.0f,
-0.75f, -0.5f, 1.0f, 0.7f, 0.0f,
0.75f, -0.5f, 1.0f, 0.7f, 0.0f,
;
void draw_rect(GLuint shader_program_id, glm::vec2 position);
#endif
rect.cpp
#include "rect.h"
void draw_rect(GLuint shader_program_id, glm::vec2 position)
glUseProgram(shader_program_id);
GLuint vao, vbo;
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(rect_vertices), rect_vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*) 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(2 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
//glm::mat4 model;
//glm::mat4 view;
//glm::mat4 projection;
//model = glm::translate(model, glm::vec3(position, 0.0f));
//glUniformMatrix4fv(glGetUniformLocation(shader_program_id, "model"), 1, GL_FALSE, glm::value_ptr(model));
//view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
//glUniformMatrix4fv(glGetUniformLocation(shader_program_id, "view"), 1, GL_FALSE, glm::value_ptr(view));
//projection = glm::ortho(0, 800, 0, 600, 1, 1000);
//glUniformMatrix4fv(glGetUniformLocation(shader_program_id, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
shader_ui.vert
#version 330 core
layout (location = 0) in vec2 position;
layout (location = 1) in vec3 color;
out vec3 fragColor;
void main()
gl_Position = vec4(position, 0.0f, 1.0f);
fragColor = color;
shader_ui.frag
#version 330 core
in vec3 fragColor;
out vec4 color;
void main()
color = vec4(fragColor, 1.0f);
如果我未能提供任何相关代码,请告诉我。我认为这涵盖了可能剖析问题所在的所有必要内容,但如果没有,我很乐意添加任何内容。
【问题讨论】:
【参考方案1】:您的 draw_rect() 函数在每帧分配一个新的顶点缓冲区,并且从不释放它。似乎在运行主循环一小段时间后,这些 VBO 中的足够多已经建立起来,当程序终止时释放它们需要相当长的时间。这应该是导致挂起的原因。
要解决这个问题,只需在初始化时创建一个 VBO 并在调用 glDrawArrays() 之前绑定它。当程序使用 glDeleteBuffers() 终止时,您可以释放它。
【讨论】:
哦,哇,现在看起来太明显了!我现在正在工作,但一旦我回到家,我会试一试。起初我想知道为什么 draw_cube 也不会减慢速度,但这是有道理的,因为我只在 init_cube 函数中使用 vbo 一次!感谢您的帮助!以上是关于添加额外的渲染调用时,GLFW 挂起关闭的主要内容,如果未能解决你的问题,请参考以下文章
react + redux + saga +服务器端渲染+如何停止服务器端渲染页面的额外ajax调用?
使用 strlen 时如何不为空终止符添加 +1 会导致使用 send 时发送额外的垃圾字节 [关闭]