-
Notifications
You must be signed in to change notification settings - Fork 475
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
sokol_gfx: Support for multiple contexts/windows #44
Comments
Argh, yeah, I knew that would come up sooner or later ;) For the GL and D3D11 backends this isn't a big issue, all the currently global state can be gathered in a context struct behind a single global pointer, and some sort of context concept (with a 'currently active context'). I need to come up with an idea for the Metal backend though. In C, ARC doesn't allow to store Obj-C id's in structs, that's the reason why there are so many globals in the Metal backend currently. |
I have no experience with Obj-C, but I thought there were ways to hold resources from C, with the Personally, I'm a huge fan of no-global-variables, I'd rather have an API where a context is created and every single call uses that context as first parameter, with a complete re-entrant API (even better if that means that each context can be handled by a different thread). In the meantime maybe the "makeCurrent" function, or whatever solution you finally decide to settle with, might be a platform dependent solution. One of the beautiful things of sokol_gfx is the fact that it doesn't completely hides the platform under some abstraction, shaders for instance depends on the platform, and there are slightly different ways of declaring vertices, etc... I would find perfectly fine having the makeCurrent function working only on some backends. If the makCurrent is allowed to work only on some platforms I can help with the OpenGL backend, which is the one I normally use if you want to. |
__unsafe_unretained works in structs with Obj-C ARC, but I still need to keep a strong reference somewhere so that the object won't be released. Bit of a chicken/egg problem... I'll also need to find out what the equivalent of a GL context is for other APIs (in D3D11 a device is associated with a swap chain, but I don't know if it's possible to have several devices in the same process, likewise, in Metal, the docs say one MTLDevice represents one GPU, so what is a GL context would be done through a MTLRenderPassDescriptor and Drawable (which is already provided from the outside, so Sokol wouldn't actually need any extra context switching features for Metal...) BUUUUT: ...maybe the GL Sokol backend also doesn't need anything extra... The GL context is managed outside Sokol anyway, and you would switch to another GL context with glfwMakeContextCurrent() outside of a begin_default_pass/end_pass/commit. The only thing you'd need to do is calling sg_reset_state_cache() after sg_commit() (it probably even makes sense to do this automatically in sg_commit(). Did you try if this works? // render to first window...
glfwMakeContextCurrent(w0);
sg_begin_default_pass(...);
...
sg_end_pass();
sg_commit();
sg_reset_state_cache();
// render to another window...
glfwMakeContextCurrent(w1);
sg_begin_default_pass(...);
...
sg_end_pass();
sg_commit();
sg_reset_state_cache();
... From sokol's point of view, two normal frames would be rendered, but outside sokol you're switching to another GL context between the first and second frame... If this works I'd prefer this solution (but maybe move the reset state cache into sg_commit). |
Indeed that should work on GLFW since GLFW context by default share OpenGL resources, thanks! I will definitely try that out. I haven't tested this, since I was checking if sokol would be able to work with multiple windows before actually working on it. |
You could also create unshared resources by switching to the right GL context right before calling the sg_create_xxx() functions, you just need to make sure to use the right resources with the right context later... I guess I'll try to write a little GLFW multiwindow demo later today to see if everything works as expected :) |
Hmm already found a problem with this approach... the global VAO object that's created because of OSX Core Profile requirements only exists on one context... I'll try find a stateless solution, but the naive solution (just check if a vertex array is bound, if not create and bind one) clashes with the idea that applications can do their own GL rendering... |
...I guess the best solution is indeed to have 2 new functions:
...this would only store data that's associated with a GL context, and inside sg_activate_context() I could also do the sg_reset_state_cache()... |
That looks fine for me, as said I'd rather reentrant api without global variables, buuuut that just my personal preference. It would be nice if sg_activate_context internally restores the state (reset_state_cache) |
Ok, I've started implementing context support in a branch and also wrote a small GLFW sample. I stumbled over another more important problem: I need to track in which context a resource has been created, and the resource needs to be destroyed while the same context is active (when the resource is destroyed manually). For automatic resource destruction I had to add a method So all in all it looks like this now:
/* called once after a new GL context is initialized */
sg_context sg_setup_context();
/* called after switching GL contexts */
void sg_activate_context(sg_context ctx);
/* called before discarding GL context, also destroys all context resources */
void sg_discard_context(); Here's a sample program with GLFW: https://github.com/floooh/sokol-samples/blob/contexts/glfw/multiwindow-glfw.c |
Wonderful!! thanks for being so quickly! |
This stuff is now in the master branch. I'm closing this issue. If anything pops up related to this it's better to open a new ticket. |
Quick question - will this work with two separate threads? |
Nope, the sokol header APIs all expect to be called from the same thread they have been initialized on. |
Question: can we initialize a |
It might work by running sgl_make_context() after it's associated glfwMakeContextCurrent() and sg_activate_context(), to make sure that any resource objects created by sokol-gl end up in the right GL- and sokol-gfx context but that's never been tested. sokol-gl contexts were actually intended for rendering into different render passes, not different GL contexts, but maybe it still works. The entire idea of sokol-gfx contexts is more or less just a hack to support rendering into different GL contexts, but working with multiple GL contexts is so fragile that it doesn't make much sense to attempt fixing any issues. |
Thanks for the answer. I'll see if I can get it to work with this order - I was fighting some assert errors and think I also tried using |
As far as I can see by the implementation, sokol_gfx can not support multiple windows/contexts. Maybe it is just a matter of storing the _sg_backend object and restoring it with a reset_state_cache call between contexts.
The text was updated successfully, but these errors were encountered: