theagentd wrote on Wednesday, December 16, 2015:
Hello. I've been thinking about a solution to a few problems.
- Performance issues when using multiple controllers, where polling and checking if they're still connected is quite slow. This will most likely be improved in the future as it is an open issue on GitHub, but with how OpenGL is single-threaded all milliseconds saved will lead to a performance increase, and it's safe to assume that all computers will have an extra core that a high-priority input/event polling thread can utilize.
- Unifying callbacks and guaranteeing that they're executed on a specific thread. As far as I know, there is a risk that some callbacks are called on other threads. This would simply be a way of synchronizing and buffering all callbacks into a single callback list and allowing the main thread to handle them whenever it's ready for them.
- Improve responsitivity of the game window(s). GLFW windows aren't updated (dragged, resized, maximized, top bar updated, tabbing out of fullscreen, etc) until glfwPollEvents() is called (this might differ depending on windowing system???). This is problematic when our game is loading, and it's difficult to ensure that the game's loading screen is updating at a fast enough rate for the window to remain responsive. Joystick input may also be missed as it requires polling at a high rate (another open issue that is currently being worked on).
The idea is to call glfwInit() on a separate thread (let's call it "the GLFW thread") and do all non-thread-safe calls on this thread. For example, when the game thread wants to create a window, it passes a task to the GLFW thread and awaits its completion. The job of the GLFW thread is to do joystick and input polling, and call glfwPollEvents() at a high rate to ensure that all windows remain responsive even if the rendering freezes up during load screens. All callbacks that are triggered are buffered in a synchronized queue which the game thread empties when it is ready.
The GLFW thread's loop looks something like this:
processTasksFromGameThread(); //commands that have to be run on the GLFW thread.
pollJoysticksAndGenerateEvents(); //until joystick callbacks are implemented.
This solves all three problems above. With multi-core CPUs the sometimes slow GLFW joystick/event handling can be offloaded to a separate core to make them pretty much free (although they might collide with the game's worker threads sometimes). Since it gathers all the callbacks into a queue some threading issues are resolved. Finally, all windows will remain responsive even if the rendering/game logic freezes up for some reason, which helps make the game look more "professional" and removes some of the burden of making sure that the game's load screen always updates regularly, something many games don't do correctly. Rendering can continue as usual since I'll just bind the OpenGL context to the game's thread like before.
Does this seem like a sane thing to do? Are there any problems with doing this?