Как ограничить количество кадров в секунду в окне GLFW? (Используя Dear ImGui)

В настоящее время мое приложение Dear ImGui (в основном демонстрационное окно с некоторым пользовательским рендерингом OpenGL) работает со скоростью 2000 кадров в секунду, если мое окно достаточно маленькое. Как я могу ограничить это частотой обновления монитора (или даже 60fps)?

Мой текущий код выглядит так:

static void glfw_error_callback(int error, const char * description)
{
    fprintf(stderr, "Glfw Error %d: %s\n", error, description);
}

int main(int, char **)
{
    // Setup window
    glfwSetErrorCallback(glfw_error_callback);
    if (!glfwInit())
        return 1;
    const char * glsl_version = "#version 150";
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);  // 3.2+ only
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);            // Required on Mac

    glfwWindowHint(GLFW_REFRESH_RATE, 60);

    // Create window with graphics context
    GLFWwindow * window = glfwCreateWindow(1280, 720, "Dear ImGui GLFW+OpenGL3 example", NULL, NULL);
    if (window == NULL)
        return 1;
    glfwMakeContextCurrent(window);
    glfwSwapInterval(1);  // Enable vsync

    bool err = gl3wInit() != 0;
    if (err) {
        fprintf(stderr, "Failed to initialize OpenGL loader!\n");
        return 1;
    }

    // Setup Dear ImGui binding
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGuiIO & io = ImGui::GetIO();
    (void)io;
    // io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;  // Enable Keyboard Controls

    ImGui_ImplGlfw_InitForOpenGL(window, true);
    ImGui_ImplOpenGL3_Init(glsl_version);

    // Other stylistic setup
    ...

        while (!glfwWindowShouldClose(window))
    {
        glfwPollEvents();
        // Create ImGui Windows
        // Rendering
        ImGui::Render();
        int display_w, display_h;
        glfwMakeContextCurrent(window);
        glfwGetFramebufferSize(window, &display_w, &display_h);
        glViewport(0, 0, display_w, display_h);
        glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
        glClear(GL_COLOR_BUFFER_BIT);
        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

        glfwMakeContextCurrent(window);
        glfwSwapBuffers(window);
    }

    // Cleanup
    return 0;
}

Как видите, он не отличается (почти совсем) от исходного примера кода для GLFW и OpenGL 3, приведенного в примерах ImGui, за исключением моей неудачной попытки ограничить частоту обновления с помощью glfwWindowHint(GLFW_REFRESH_RATE, 60), который я узнал, влияет только на окно в полноэкранном режиме. Кроме того, я думал, что glfwSwapInterval(1) может также ограничивать частоту обновления до частоты обновления монитора, но, похоже, этого тоже не происходит. Любая помощь приветствуется.

Редактировать: функция ошибки GLFW и загрузка.

3 ответа

Установка glfwSwapInterval(0); снимает рамку.

Я бы использовалglfwSwapInterval(1). По сути, это включит vsync, который будет запускать вашу программу с той же частотой кадров в секунду, что и частота обновления вашего монитора.

В моих экспериментах сglfwSwapInterval()какое бы число вы ни вставили в эту функцию, результат будет

(частота обновления монитора, измеряемая вhertz)/(number entered) = (application fps)#Среднее значение приложения в мс/кадр увеличится

      360hz/0 = 2400fps   #~.3 ms/frame (used ~70% of my gpu(3070ti) for the Demo Page)

360hz/1 = 360fps   #~2.7 ms/frame

360hz/2 = 180fps   #~5.5 ms/frame

360hz/4 = 90fps    #~11.12 ms/frame

360hz/6 = 60fpsf   #~16.6 ms/frame

установка 0 приведет к тому, что ваш компьютер будет запускать вашу программу максимально быстро, не рекомендую

Если вы знаете, на каком мониторе работает ваша программа, это легко исправить, но если вы его распространяете, это может стать немного неудобным. Мой монитор работает с частотой обновления 360 Гц, поэтому значение 6 приведет к тому, что моя программа будет работать со скоростью 60 кадров в секунду. Но тогда моя программа будет работать со скоростью всего 10 кадров в секунду на мониторе с частотой 60 Гц, что до сих пор очень распространено, особенно на рабочем месте. Частота обновления также будет увеличиваться по мере совершенствования технологий, поэтому в долгосрочной перспективе это не лучшее решение. Я считаю, что в наши дни продаются мониторы с частотой 500 Гц. Тем не менее, это может не иметь большого значения в зависимости от вашего варианта использования.

Еще одна проблема, которую я обнаружил, заключается в том, что если у вас несколько мониторов, ваш fps будет меняться в зависимости от того, на каком мониторе работает ваше приложение. У меня оно может колебаться от 360 до 220 или 180 в зависимости от того, на каком мониторе включен мой графический интерфейс. Что-то, что я могу оставить в себе

Для людей, которые ищут способ ограничить частоту кадров:

вы можете запустить функцию задержки, написанную следующим образом

      void delay()
{
    auto start = std::chrono::high_resolution_clock::now();
    auto stop = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
    while (true)
    {
        stop = std::chrono::high_resolution_clock::now();
        duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
        if (duration.count() >= 20000)
        {
            return;
        }
        else
            continue;
    }
}

внутри основного цикла imgui ^^ возможно есть другой способ сделать это, но я нашел это очень удобным.

Другие вопросы по тегам