添加额外的渲染调用时,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 挂起关闭的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI 中自定义网格视图的额外不必要渲染问题

我应该如何在函数视图中调用基于类的通用视图

react + redux + saga +服务器端渲染+如何停止服务器端渲染页面的额外ajax调用?

使用 strlen 时如何不为空终止符添加 +1 会导致使用 send 时发送额外的垃圾字节 [关闭]

在 Symfony 2.1 中为 preUpdate 调用添加额外的持久化调用

在现有的 android 调用应用程序中添加一个额外的按钮?