korge
korge copied to clipboard
AG improvements
AG right now only support full batches. Let’s do some improvements:
- [x] Separate render queues, with incremental state changes
- [x] Support Uniform Objects
- [x] Support Vertex Array Objects
- [ ] Integrate with multithreaded rendering, to offload and to have the main app loop execute tasks as they are available without waiting for vsync
Current State
Currently we have a synchronous rendering engine, that takes a state and a set of vertices and renders it synchronously in the current thread. This has several drawbacks: it requires setting the full state, and requires logic code to be executed on the main rendering thread, so it blocks while rendering, and also blocks while waiting for vsync, preventing pending tasks like I/O or short lived suspension points to wait one full frame to be executed. Also prevents vector rendering technique to be effective, since it executes lots of small commands with really small state changes.
Expected State
Have the rendering UI thread working in one thread (or multiple threads when using vulkan, metal, or webgpu) consuming queued indirect GPU commands. The main dispatcher will run in a separate thread, specially now that K/N is starting to support a new memory model and will be easier to have several threads. This thread will continue being single thread, to avoid concurrency issues altogether. This thread will execute logic code, and potentially also indirect rendering code that will issue commands to the queue without waiting for them to be executed, except for sync points (like reading a texture). But waiting will be possible to happen asynchronously with a CompletableDeferred/suspension. This thread won't wait for vsync, but will execute the rendering in this thread once vsync is triggered by the rendering thread.
Incremental proposal
To do this incrementally, what I'm doing right now is:
I have created an AGList that represents the queue, and provides some commands really similar to opengl, but simplified. This has a queue, and now there is a consumer of that queue written for OpenGL: AGQueueProcessorOpenGL.
To start using it already, the AGOpengl.draw method is now creating a queue, and using the queueprocessor to consume it synchronously. So it alreayd emits some commands, but processes it synchronously after that.
Once we have all the commands available, AGOpengl.draw will be moved to AG directly, and we will be able to emit small commands synchronously in the same thread, benefiting the GPU vector rendering.
And after that we will be able to start modeling the multithreaded rendering: one thread for rendering on the UI, and other thread for the logic and main single-threaded dispatcher (similar to JS).
Once it works properly after some time on all the targets, we will enable it by default.
And after opengl processor is working properly in multiple threads, we should be able to start providing a consumer for metal, vulkan and/or webgpu.