Linux: Only process global state when something interesting happens
This matches behavior on macOS. Had initially set the code to process on every loop tick in an attmept to workaround the issue of the event loop freezing on X11 until an X event is delivered. However, in light of #1782 that workaround was incorrect anyway. Better to have similar behavior across platforms. This also has the advantage of reducing CPU consumption. Also add a simple program to test event loop wakeups.
This commit is contained in:
parent
63573d6e26
commit
8244f7cd58
25
glfw/main_loop.h
vendored
25
glfw/main_loop.h
vendored
@ -12,9 +12,11 @@
|
||||
#define GLFW_LOOP_BACKEND x11
|
||||
#endif
|
||||
|
||||
static bool keep_going = false;
|
||||
static bool keep_going = false, tick_callback_requested = false;
|
||||
|
||||
void _glfwPlatformRequestTickCallback() {
|
||||
EVDBG("tick_callback requested");
|
||||
tick_callback_requested = true;
|
||||
}
|
||||
|
||||
void _glfwPlatformStopMainLoop(void) {
|
||||
@ -24,15 +26,26 @@ void _glfwPlatformStopMainLoop(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwPlatformRunMainLoop(GLFWtickcallback tick_callback, void* data) {
|
||||
keep_going = true;
|
||||
while(keep_going) {
|
||||
_glfwPlatformWaitEvents();
|
||||
EVDBG("loop tick");
|
||||
static inline void
|
||||
dispatch_tick_callbacks(GLFWtickcallback tick_callback, void *data) {
|
||||
while (tick_callback_requested) {
|
||||
EVDBG("Calling tick callback");
|
||||
tick_callback_requested = false;
|
||||
tick_callback(data);
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwPlatformRunMainLoop(GLFWtickcallback tick_callback, void* data) {
|
||||
keep_going = true;
|
||||
tick_callback_requested = false;
|
||||
while(keep_going) {
|
||||
EVDBG("loop tick, tick_callback_requested: %d", tick_callback_requested);
|
||||
dispatch_tick_callbacks(tick_callback, data);
|
||||
_glfwPlatformWaitEvents();
|
||||
}
|
||||
EVDBG("main loop exiting");
|
||||
}
|
||||
|
||||
unsigned long long _glfwPlatformAddTimer(double interval, bool repeats, GLFWuserdatafreefun callback, void *callback_data, GLFWuserdatafreefun free_callback) {
|
||||
return addTimer(&_glfw.GLFW_LOOP_BACKEND.eventLoopData, "user timer", interval, 1, repeats, callback, callback_data, free_callback);
|
||||
}
|
||||
|
||||
@ -889,14 +889,9 @@ set_cocoa_pending_action(CocoaPendingAction action, const char *wd) {
|
||||
static void process_global_state(void *data);
|
||||
|
||||
static void
|
||||
do_state_check(id_type timer_id UNUSED, void *data UNUSED) {
|
||||
do_state_check(id_type timer_id UNUSED, void *data) {
|
||||
EVDBG("State check timer fired");
|
||||
#ifdef __APPLE__
|
||||
process_global_state(data);
|
||||
#endif
|
||||
// We don't actually do anything here as process_global_state
|
||||
// will be called when the loop ticks on Linux
|
||||
|
||||
}
|
||||
|
||||
static id_type state_check_timer = 0;
|
||||
@ -937,7 +932,8 @@ process_global_state(void *data) {
|
||||
if (global_state.has_pending_closes) has_open_windows = process_pending_closes(self);
|
||||
if (has_open_windows) {
|
||||
if (maximum_wait >= 0) {
|
||||
state_check_timer_enabled = true;
|
||||
if (maximum_wait == 0) request_tick_callback();
|
||||
else state_check_timer_enabled = true;
|
||||
}
|
||||
} else {
|
||||
stop_main_loop();
|
||||
|
||||
18
kitty/glfw.c
18
kitty/glfw.c
@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "state.h"
|
||||
#include "glfw_tests.h"
|
||||
#include "fonts.h"
|
||||
#include <structmember.h>
|
||||
#include "glfw-wrapper.h"
|
||||
@ -27,11 +28,9 @@ static GLFWcursor *standard_cursor = NULL, *click_cursor = NULL, *arrow_cursor =
|
||||
static void set_os_window_dpi(OSWindow *w);
|
||||
|
||||
|
||||
static void
|
||||
void
|
||||
request_tick_callback(void) {
|
||||
#ifdef __APPLE__
|
||||
glfwRequestTickCallback();
|
||||
#endif
|
||||
}
|
||||
|
||||
static int min_width = 100, min_height = 100;
|
||||
@ -1150,6 +1149,18 @@ stop_main_loop(void) {
|
||||
glfwStopMainLoop();
|
||||
}
|
||||
|
||||
|
||||
static PyObject*
|
||||
test_empty_event(PYNOARG) {
|
||||
|
||||
int ret = empty_main();
|
||||
if (ret != EXIT_SUCCESS) {
|
||||
PyErr_Format(PyExc_RuntimeError, "Empty test returned failure code: %d", ret);
|
||||
return NULL;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
// Boilerplate {{{
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
@ -1178,6 +1189,7 @@ static PyMethodDef module_methods[] = {
|
||||
{"glfw_get_key_name", (PyCFunction)glfw_get_key_name, METH_VARARGS, ""},
|
||||
{"glfw_primary_monitor_size", (PyCFunction)primary_monitor_size, METH_NOARGS, ""},
|
||||
{"glfw_primary_monitor_content_scale", (PyCFunction)primary_monitor_content_scale, METH_NOARGS, ""},
|
||||
{"glfw_test_empty_event", (PyCFunction)test_empty_event, METH_NOARGS, ""},
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
||||
112
kitty/glfw_tests.c
Normal file
112
kitty/glfw_tests.c
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* glfw_tests.c
|
||||
* Copyright (C) 2019 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#include "glfw_tests.h"
|
||||
|
||||
|
||||
#include "glfw-wrapper.h"
|
||||
#include "gl.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
static volatile bool running = true;
|
||||
|
||||
static void* empty_thread_main(void* data UNUSED)
|
||||
{
|
||||
struct timespec time = { .tv_sec = 1 };
|
||||
|
||||
while (running)
|
||||
{
|
||||
nanosleep(&time, NULL);
|
||||
glfwRequestTickCallback();
|
||||
glfwPostEmptyEvent();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void key_callback(GLFWwindow *w UNUSED, int key, int scancode UNUSED, int action, int mods UNUSED, const char* text UNUSED, int state UNUSED)
|
||||
{
|
||||
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
|
||||
glfwSetWindowShouldClose(w, true);
|
||||
wakeup_main_loop();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
window_close_callback(GLFWwindow* window) {
|
||||
glfwSetWindowShouldClose(window, true);
|
||||
glfwRequestTickCallback();
|
||||
wakeup_main_loop();
|
||||
}
|
||||
|
||||
|
||||
static float nrand(void)
|
||||
{
|
||||
return (float) rand() / (float) RAND_MAX;
|
||||
}
|
||||
|
||||
static void
|
||||
empty_main_tick(void *data) {
|
||||
GLFWwindow *window = data;
|
||||
if (glfwWindowShouldClose(window)) {
|
||||
running = false;
|
||||
glfwStopMainLoop();
|
||||
return;
|
||||
}
|
||||
int width, height;
|
||||
float r = nrand(), g = nrand(), b = nrand();
|
||||
float l = (float) sqrt(r * r + g * g + b * b);
|
||||
|
||||
glfwGetFramebufferSize(window, &width, &height);
|
||||
|
||||
glViewport(0, 0, width, height);
|
||||
glClearColor(r / l, g / l, b / l, 1.f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glfwSwapBuffers(window);
|
||||
}
|
||||
|
||||
int empty_main(void)
|
||||
{
|
||||
pthread_t thread;
|
||||
GLFWwindow* window;
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, OPENGL_REQUIRED_VERSION_MAJOR);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, OPENGL_REQUIRED_VERSION_MINOR);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, true);
|
||||
|
||||
|
||||
srand((unsigned int) time(NULL));
|
||||
|
||||
window = glfwCreateWindow(640, 480, "Empty Event Test", NULL, NULL);
|
||||
if (!window)
|
||||
{
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
gl_init();
|
||||
glfwSetKeyboardCallback(window, key_callback);
|
||||
glfwSetWindowCloseCallback(window, window_close_callback);
|
||||
|
||||
if (pthread_create(&thread, NULL, empty_thread_main, NULL) != 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to create secondary thread\n");
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
glfwRunMainLoop(empty_main_tick, window);
|
||||
|
||||
glfwHideWindow(window);
|
||||
pthread_join(thread, NULL);
|
||||
glfwDestroyWindow(window);
|
||||
|
||||
return (EXIT_SUCCESS);
|
||||
}
|
||||
11
kitty/glfw_tests.h
Normal file
11
kitty/glfw_tests.h
Normal file
@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "state.h"
|
||||
|
||||
int empty_main(void);
|
||||
@ -234,6 +234,7 @@ bool application_quit_requested(void);
|
||||
void request_application_quit(void);
|
||||
#endif
|
||||
void request_frame_render(OSWindow *w);
|
||||
void request_tick_callback(void);
|
||||
typedef void (* timer_callback_fun)(id_type, void*);
|
||||
typedef void (* tick_callback_fun)(void*);
|
||||
id_type add_main_loop_timer(double interval, bool repeats, timer_callback_fun callback, void *callback_data, timer_callback_fun free_callback);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user