If you guys aren't going to consider going down that road my vote is to let SFML keep handling the context(s). Nothing stops people from using OpenGL directly in SFML, and those that don't want to don't have to.That's one of the main problem with contexts managed by SFML. If you want to use OpenGL directly, you're still bound to how SFML handles the contexts internally. You'll have to hack around whatever SFML does with the contexts and you can't handle things the way you want.
But this is not enough to draw conclusions, I think we should write and publish an application that runs the same tests, and have as many users as possible to test it, to validate these assumptions on a wide range of OSes, GPUs and drivers.I could do that... But, you have to remember, the way SFML handles context management is so unique, that when we say we consider changing it to look different, it might in fact end up looking like what other libraries have already done for a very long time. If some of the assumptions are not true, those libraries would have already ceased to function properly long ago.
I also remember that you already came up with significant improvements to the internal code (based on the above assumptions), so with these improvements, would we still need explicit context management?If you are referring to gl_dev, then no, that branch doesn't touch context management in any way. It just focuses on replacing GLEW without changing any functionality, and after that, adding support for things people have wanted for a long time. The context management still looks the same as it did without the changes.
The way I see it, sfml-graphics has to be rewritten to build on top of sfml-window more than it does now. There is still too much coupling between the modules for my taste. Hopefully with the module restructuring in SFML 3, we can try to solve this issue as well.
Are you saying that every sf::GlResource will not be freed until the termination of the program?No... You control the lifetime of your sf::GlResources, and they will be freed when you choose to do so. It is the internal contexts that will not be freed until the termination of the program (or at least the destruction of every sf::GlResource, which ends up being the same in typical cases), due to the threading constraints I mentioned. The problem is that the internal contexts are managed in part using thread-local storage, and at least on Windows, the assumption is that the code which spawns the thread should also be responsible for allocating and deallocating objects stored in TLS. This is broken in SFML, since it uses TLS "behind the scenes" and lets the user create threads at will. Windows doesn't provide a simple way for SFML to detect when a thread is going to terminate from within the terminating thread. This last part is important, because it is that thread that has to deactivate the context so it can be freed. Strictly speaking, the way SFML destroys its internal contexts during global cleanup in the main thread isn't necessarily correct, since they weren't deactivated in the threads that had already terminated a long time ago. Why doesn't this cause an error to be returned by the operating system? Maybe they decided to be a bit lax regarding this matter, who knows...
I get what you're saying about having the internal context and looking at ways to prevent these unnecessary globals, but does the context sharing create serious memory leaks?The context sharing does not create leaks itself, it is the fact that the way SFML asserts that there always has to be a context active on every thread that makes it impossible to free the internal contexts until SFML is sure that no more sf::GlResources depend on contexts any longer (which can only happen in the scenario I just mentioned). Context sharing is only insofar an "issue", due to the fact that SFML currently uses a dedicated context to share with the others, although this dedicated context doesn't do anything useful otherwise.
Wouldn't that mean sfml-graphics would depend on sfml-window? That seems counterintuitive to the goal of reducing coupling?sfml-graphics already depends on sfml-window. But as I see it now, certain things, like extension loading and raw OpenGL object management should be moved out of sfml-graphics and perhaps into a dedicated opengl module. That in turn would be what people that want simplified access to OpenGL objects in a RAII manner would be using, and that would also alleviate them of having to rely on SFML context management when they choose to do it themselves.
- If all your rendering is done in a single thread, then in principle you can create a single context at the beginning of the thread, destroy it when the thread dies (or just use RAII), and never think about contexts once in the rest of your code.
- For the vast majority of simple apps, and probably a lot of complex ones, rendering is best done in a single thread anyway,
- The people who are interested in using raw OpenGL or multiple threads or multiple OpenGL contexts are sophisticated users that can and want to manage such things themselves.
- If the shared context and internal contexts and RenderTexture contexts were simply erased from SFML, it would have no real effect on a program with only one thread.
- Even if all implicit context management were erased from SFML, the burden to the beginner would probably consist of nothing more than writing "sf::Context context;" at the start of his main() function.
- Even for advanced users, there aren't very many things an explicit context management API would have to include. All I can think of is: create and destroy a context, share contexts with each other, activate and deactivate contexts for the current thread, pass contexts to another thread, and construct framebuffers/vertex array objects bound to a given context. And sf::Context already has some of that.
- It's possible to have implicit and explicit context management coexist in a relatively simple and intuitive way, such as having sf::GlResources secretly construct one (and only one!) context if they find that the user never created one themselves in that thread.
- Certain methods like the static sf::Shader::isAvailable() that (somewhat unintuitively) require an OpenGL context might be better off as non-static methods like sf::Context::areShadersAvailable().
- The only "benefit" of the way SFML context management currently works is that if you're passing drawable objects between threads, a draw() command will never fail because you made a contex-related error. But beginners probably shouldn't do multithreading in the first place, and it does nothing to stop the "white square problem", so it's a pretty weak benefit.
If all your rendering is done in a single thread, then in principle you can create a single context at the beginning of the thread, destroy it when the thread dies (or just use RAII), and never think about contexts once in the rest of your code.This is true.
For the vast majority of simple apps, and probably a lot of complex ones, rendering is best done in a single thread anywayFor almost all apps, and especially ones that exploit the latest and greatest OpenGL. Even guys from Nvidia and AMD say that internally, the driver has to synchronize anyway and you would not gain much if anything at all from putting much into a secondary thread. People who still believe stuff like this are simply misguided and too stubborn to realize things have changed over the years.
The people who are interested in using raw OpenGL or multiple threads or multiple OpenGL contexts are sophisticated users that can and want to manage such things themselves.You only really need multiple OpenGL contexts if you multi-thread your OpenGL which doesn't offer that many benefits as I already mentioned. Often people are too lazy to separate out the non-OpenGL stuff from the OpenGL stuff because "putting OpenGL stuff into a separate thread works anyway right?".
If the shared context and internal contexts and RenderTexture contexts were simply erased from SFML, it would have no real effect on a program with only one thread.This is true. In fact, getting rid of the shared context is fairly trivial. One could just use a guarded std::set containing all currently existing contexts to share with future ones. Laurent chose to have a separate shared context, because according to him, sharing with contexts that were active didn't work for him back then...
Even if all implicit context management were erased from SFML, the burden to the beginner would probably consist of nothing more than writing "sf::Context context;" at the start of his main() function.The context is used to choose a target for draw commands, thus it would have to be bound to the window that is created before it. Currently every context that isn't bound to a visible window has an "in-memory window". This is also the reason why creating/destroying FBO sf::RenderTextures in fullscreen causes flicker, windows are created and destroyed in the background.
Even for advanced users, there aren't very many things an explicit context management API would have to include. All I can think of is: create and destroy a context, share contexts with each other, activate and deactivate contexts for the current thread, pass contexts to another thread, and construct framebuffers/vertex array objects bound to a given context. And sf::Context already has some of that.This is true. In my modern GL test sandbox I also use for testing gl_dev, I run all graphics in a single thread, and I also resort to semi-manual context management by instantiating my own sf::Contexts from time to time.
It's possible to have implicit and explicit context management coexist in a relatively simple and intuitive way, such as having sf::GlResources secretly construct one (and only one!) context if they find that the user never created one themselves in that thread.This is not that simple. The whole idea of this discussion is to get rid of all the stuff that happens secretly, especially because they are the things causing problems. SFML wouldn't be allowed to assume the user would have did it anyway, because getting rid of contexts that were unintentionally created is a very difficult task. I still agree though, that if a user decides that they really want to go down the path of doing sfml-graphics in a separate thread, they should be required to understand that they need to manage the secondary context on their own.
Certain methods like the static sf::Shader::isAvailable() that (somewhat unintuitively) require an OpenGL context might be better off as non-static methods like sf::Context::areShadersAvailable().This is also something I considered a long time ago. Instead of having each class probe for specific capabilities on their own, there should be a centralized way of doing so. Many other libraries already allow the user to use a single point to probe any/all capabilities the card supports. As an example of stuff an advanced SFML user (who doesn't use any raw OpenGL whatsoever) would want to probe: How many uniforms does the current hardware support? If they did not know this, some shaders would simply not work on specific hardware.
The only "benefit" of the way SFML context management currently works is that if you're passing drawable objects between threads, a draw() command will never fail because you made a contex-related error. But beginners probably shouldn't do multithreading in the first place, and it does nothing to stop the "white square problem", so it's a pretty weak benefit.This is true, and probably the most important point to understand. SFML currently makes a lot of sacrifices in order to hide the true complexity of multi-threading graphics related development. It isn't a good idea to start with, and if you ask me, SFML shouldn't hide its true nature from the beginner only so that they can discover its problems further down the road.
In order to have a render target (Window or RenderTexture, for example) you must have a context bound to that target.This is only partially true.
Every context is bound to a render target, even if to a "virtual" and useless oneIf by that you mean "has a framebuffer", then yes... This is one of the things I mentioned in my original post.
Each context can only be used by one thread at a time, so you can't use multiple threads to draw to the same render targetYou can use multiple threads to draw to the same render target. What people don't fully understand is that you have to manually call .setActive(false) in the previous thread before drawing from a secondary thread. There is currently no thread-to-thread communication to "inform the previous thread to relinquish its active context" automatically. This has to be done by the user. If this is not done, .setActive(true) (called internally by sfml-graphics as well) in the secondary thread would return false to notify of failure, and nothing will be drawn.
If those points are all true and if I understood the "context leaking" problem right, then the simplest and cleanest way to solve those problems would be to have an internal SFML graphical thread (like the internal audio thread) for each render target, and all drawing operations on said render targets would be performed by that thread. You can have a poll of drawing operations for the render target and have that thread go over it whenever a new operation pops up.It's not as simple as you think, not to mention the overhead would be astronomical and simply kill performance.
You said it yourself that multithreading is useless to gain performance on the context operations, so this would keep contexts hidden and only create contexts when neccessary. That is, assuming I understood these contexts right. If the drawing operations have useful returning values, it is always possible to block the calling thread untill the drawing thread finishes the task, and get the result back afterwards.I don't understand much of what you said there. What I have said time and again is that multi-threading doesn't provide the benefits many people think they are getting when offloading graphics operations to separate threads. This has nothing to do with "context operations" whatever you meant by that. As soon as SFML has to go to OpenGL to get stuff done, if that is happening in a thread other than the main one, you are doing something wrong.
Ok, but everything you said just confirmed that my suggestion would be great.I would like to see a statement by statement reasoning for why you think this. It seems you didn't fully understand what I said.
Since graphical operations are "returnless", you can just put them on the poll, wake the drawing thread up if it is sleeping and return. It wouldn't have any delay whatsoever for the user's code, and since the operations are going to be done sequentialy anyway, you won't lose any performance (by having only one thread doing all the drawing sequentialy for each render target).It is ludicrous to think that dedicating another thread just to synchronize access to the driver would help solve this problem. I don't know how much multi-threading you have done, but you do understand that you would have to take care of data synchronization yourself in this case right? Not to mention that there are also functions that don't draw stuff but query the driver for data as well. What would you do in that case? Copy the OpenGL function signatures so you can relay these data structures back and forth as well? What about selecting the right context to draw to in multi-window applications? Would you really have to pass the context to activate along with each function that you call? What benefit does that provide over merely activating the contexts in the main thread and doing all the work there? And the part that I really don't understand is: How would this solve the problem that we are already currently having?
You've said that it would be so slow it would cease to be realtime, but why?You've taken this statement out of context. Please reread that post again if you don't understand.
Ok, I'll quote your post and answer it part by part. I didn't do that before because the topic had too much text for that, and because I wasn't sure how contexts work, even after reading everything. I don't remember ever hearing anything about OpenGL contexts before reading this topic, so I am taking all of my information from here.Ok, but everything you said just confirmed that my suggestion would be great.I would like to see a statement by statement reasoning for why you think this. It seems you didn't fully understand what I said.
What I understood from previous posts is this: OpenGL uses contexts to manage render targets, and those contexts are not "safe" for multithreading, so they have restricted each context to a single active thread. You can deactivate one thread and activate another, but you can't have two active threads on the same context, so in other words it just forces the user to do the synchronization. My suggestion is that the synchronization is done hidden inside SFML, so that the API can stay the same. The back-end particularities shouldn't have effect on SFML's public API, in my opinion (specially when we consider possible future DirectX support, for example, but lets not diverge from the topic at hand).Since graphical operations are "returnless", you can just put them on the poll, wake the drawing thread up if it is sleeping and return. It wouldn't have any delay whatsoever for the user's code, and since the operations are going to be done sequentialy anyway, you won't lose any performance (by having only one thread doing all the drawing sequentialy for each render target).It is ludicrous to think that dedicating another thread just to synchronize access to the driver would help solve this problem. I don't know how much multi-threading you have done, but you do understand that you would have to take care of data synchronization yourself in this case right?
Not to mention that there are also functions that don't draw stuff but query the driver for data as well. What would you do in that case? Copy the OpenGL function signatures so you can relay these data structures back and forth as well?I didn't know we had to synchronize data retrival functions as well. As I've said before, I only know this issue from what I've read here, so if I don't know all of the problems my suggestions will be flawed from the start. How does data retrieval work on OpenGL? Is it thread-safe? Does it support parallel data retrival on multiple threads? Does it use the contexts for that? In what way? I am realy clueless to this point.
What about selecting the right context to draw to in multi-window applications? Would you really have to pass the context to activate along with each function that you call? What benefit does that provide over merely activating the contexts in the main thread and doing all the work there? And the part that I really don't understand is: How would this solve the problem that we are already currently having?You wouldn't have to pass the context, since the Window object would have its context internaly. The benefit of my suggestion would be that you wouldn't have to worry about the synchronization at all when drawing stuff, the Window's internal thread will do the "talking" with OpenGL and everything will just work. Also, we wouldn't need more contexts than the number of render targets, if my understanding of contexts is correct, but I might be wrong.
You say that drawing stuff on multiple threads is bad practice, but it is only bad practice if it creates unsolveable issues or if it affects resource usage significantly. Sure, you shouldn't draw from multiple threads on the same context in parallel in OpenGL, but we are talking about SFML, and as long as we can solve OpenGL's issues ourselves without affecting the performance significantly, we can choose our own way of presenting features to the user. In my opinion, the interface should only show an issue to the user if it can't be solved internaly.You've said that it would be so slow it would cease to be realtime, but why?You've taken this statement out of context. Please reread that post again if you don't understand.
SFML, and other middleware has done this a lot. They are so desperate to appeal to developers with bad practices or little understanding of the subject matter, that they end up having to hide the real problems from them. Instead of saying "don't worry, you can do what you have always been doing although it is a bad idea" why not say "you know... that is not such a good idea, why not try it like this instead"? Sure some will always complain and threaten to go to another library that keeps pampering them. But trying to keep a hold of those with objectively very very bad practices to the detriment of others willing to improve is not something I feel good about either.
I'm not saying that we need to change the way SFML does context management overnight. I'm pretty sure it is possible to keep it the way it is while dealing with some, but not all of the problems that arise. Going out of our way by introducing an additional thread just for rendering, is unheard of, and I've seen a lot over the last years.Ok, it is unheard of, but would it work? What are the possible drawbacks? Is the number of threads limited to less than the number of possible contexts on an application? Would multiple sleeping threads (since the threads will be mostly sleeping, except when waken to draw stuff and sleep again) affect the performance of the user's thread? Would those sleeping threads compromise memory in any significant way? You have also mentioned data retrieval, and I would like to know how that is done on OpenGL (to try and adapt the "internal thread solution", if it passes the previous questions).
Also, what Ixrec said should be universally true. The amount of effort required to get something done should always be proportional to the complexity of what you want done. Reducing the effort by a flat amount regardless of the complexity leads to situations like the one we have now. If the user wants to multi-thread sfml-graphics, I will tell them that I do not recommend doing it, but it is up to them what their code looks like, and if they are that desperate to do it, they can read a bit more about multi-threaded context management. If you ask me, the effort required to multi-thread properly is much much larger than the effort required to understand how contexts are used in different threads. Most of the time, unfortunately, people fail to do the former already, and we are trying to help hide the latter from them.So, you are suggesting that since multithreading OpenGL contexts efficiently is hard, you should just force SFML users to do it themselves and give the "OpenGL context" problem to them? I might well be underestimating the problems here (and I probably am), but until I understand the problem I won't assume it is unsolveable, so I am sorry if I am talking nonsense.
What I understood from previous posts is this: OpenGL uses contexts to manage render targets, and those contexts are not "safe" for multithreading, so they have restricted each context to a single active thread. You can deactivate one thread and activate another, but you can't have two active threads on the same context, so in other words it just forces the user to do the synchronization.All that is important to know, I already mentioned in the list in the original post. You can multi-thread with contexts safely, you just have to keep those constraints in mind. Instead of activating and deactivating threads, which I never talked anywhere about, you activate and deactivate contexts. Even if a thread is "inactive" whatever that means, if a context is still active on that thread, it won't be able to be activated anywhere else. You have to consider things from the context's point of view and not the thread's point of view.
My suggestion is that the synchronization is done hidden inside SFML, so that the API can stay the same.This is the way it currently is, and if you've read what has already been posted in this thread again, you will see that this leads to problems. And before you say anything else, no, your solution will not solve any of these problems. It will merely create more of them.
The back-end particularities shouldn't have effect on SFML's public API, in my opinion (specially when we consider possible future DirectX support, for example, but lets not diverge from the topic at hand).The aim of this discussion is to try and find a solution for the current situation. Simply saying "hide all the ugly stuff for me so that alternate renderers will look just as simple" still doesn't change the fact that that "stuff" that is hidden is problematic. And, in case people didn't know yet, SFML was designed with OpenGL in mind. I have not made many thoughts on how it would have to change to support multiple renderers, but I am pretty sure that you won't be able to recognize similarities between the new and old implementation when it gets done one day.
I didn't know we had to synchronize data retrival functions as well. As I've said before, I only know this issue from what I've read here, so if I don't know all of the problems my suggestions will be flawed from the start. How does data retrieval work on OpenGL? Is it thread-safe? Does it support parallel data retrival on multiple threads? Does it use the contexts for that? In what way? I am realy clueless to this point.Data retrieval isn't as complicated as you think, but that still doesn't mean you don't have to give it a bit of thought. It can have many manifestations. The most common and simple one is getting a single state value from the driver. This can be different depending on which context is active when you call the respective function. For things like taking screenshots, it is a bit more complicated. You will have to pass in a correctly sized array so that the GL can write the data you request from it into the array. This is also context dependent, and is a rather slow operation since we are reading data directly from the GPU.
You wouldn't have to pass the context, since the Window object would have its context internaly. The benefit of my suggestion would be that you wouldn't have to worry about the synchronization at all when drawing stuff, the Window's internal thread will do the "talking" with OpenGL and everything will just work. Also, we wouldn't need more contexts than the number of render targets, if my understanding of contexts is correct, but I might be wrong.This is worse than I expected... Now I understand that you were aiming to have a separate "rendering thread" for each context that can be used in some way... just so you can omit having to constantly select which one to activate? There are beginners on this forum... that just start out with game development, and after not too long, even they understand that having more threads than necessary is not a good thing. I don't know where you are coming from, but if you think that resorting to creating an excessive number of threads to get anything done is a good idea, I am sorry to have to tell you that you are mistaken. The same is said to beginners as well as advanced developers: Avoid threads while you can. Unless you know exactly why they provide a benefit, you won't gain much from them.
You say that drawing stuff on multiple threads is bad practice, but it is only bad practice if it creates unsolveable issues or if it affects resource usage significantly.If that is the case, then you must also oppose usage of smart pointers over raw pointers too right? Raw pointers don't create unsolvable issues and have better resource usage than smart pointers, and yet the universal opinion from any established C++ programmer is that you should rarely ever use raw pointers (and certainly not owning ones) in modern C++ code.
Sure, you shouldn't draw from multiple threads on the same context in parallel in OpenGL, but we are talking about SFML, and as long as we can solve OpenGL's issues ourselves without affecting the performance significantly, we can choose our own way of presenting features to the user. In my opinion, the interface should only show an issue to the user if it can't be solved internaly.Sure... here at SFML, we like to create our own concepts that users have to embrace to use SFML efficiently. But that still doesn't change the fact that those concepts have to map to "real-world" implementations. There are still connections between the two. And as uncomfortable as it is, it is not possible to hide every single implementation detail from seeping through the API to the user. Maybe SFML users are merely using SFML as a stepping stone on their way towards more advanced graphics programming? You never know. But twisting reality just because we can isn't something we do. We simplify it, where we can. Where we can't, we have to pass it on to the user. And the whole point of this discussion is that initially, SFML thought that it could hide the complexities of multi-threaded OpenGL without causing too many problems, but over time that assumption has lost more and more weight, which is why we are in our current situation.
Ok, it is unheard of, but would it work?You tell me... I am not going to go ahead and spend 10s maybe even 100s of hours implementing something I find problematic from the start. From reading what you have proposed, I would say, yeah, it can work, but have fun with your 2 FPS applications. Ultimately, most ideas in software development, no matter how crazy they are, can be implemented. You just have to spend a varying amount of time dealing with the effects you did not anticipate during brainstorming.
What are the possible drawbacks? Is the number of threads limited to less than the number of possible contexts on an application? Would multiple sleeping threads (since the threads will be mostly sleeping, except when waken to draw stuff and sleep again) affect the performance of the user's thread? Would those sleeping threads compromise memory in any significant way?I've already reiterated over the drawbacks enough times in the last posts and this one. If you still don't understand them, please read them again. I assume that you are somewhat familiar with threading (and more importantly efficient multi-threading), since you often propose "solutions" to problems that involve them in some way. So can't you just draw your own conclusions? If this is not the case, i.e. you are not experienced in threading, then I highly recommend you refrain from using them in any future solutions you propose anywhere. I don't mean to be offensive, but these solutions don't necessarily make you look good...
You have also mentioned data retrieval, and I would like to know how that is done on OpenGL (to try and adapt the "internal thread solution", if it passes the previous questions).I already mentioned this above. And instead of relying on my spending well over an hour typing a reply for you, why don't you do a bit of research on your own? ;) OpenGL isn't that hard to understand, especially if you concentrate on specific parts of the API.
So, you are suggesting that since multithreading OpenGL contexts efficiently is hard, you should just force SFML users to do it themselves and give the "OpenGL context" problem to them? I might well be underestimating the problems here (and I probably am), but until I understand the problem I won't assume it is unsolveable, so I am sorry if I am talking nonsense.What you misunderstand, is that the majority of users probably won't be affected code-wise by any changes. They already assume that performing all OpenGL related stuff within the main thread is the way to go, and like I said, there is no reason to annoy these users. It is the ones who already resort to bad practice that will have to potentially make small adjustments to their code. Maybe this is a signal to them that what they are doing is not a good idea. If this motivates them to change the way they think of using sfml-graphics to single threaded, then I am nothing but happy.
I meant to say that you can deactivate a context on a thread and activate it on another thread, but you can't activate it on multiple threads at the same time. I though it was obvious, but sorry for the bad wording.What I understood from previous posts is this: OpenGL uses contexts to manage render targets, and those contexts are not "safe" for multithreading, so they have restricted each context to a single active thread. You can deactivate one thread and activate another, but you can't have two active threads on the same context, so in other words it just forces the user to do the synchronization.All that is important to know, I already mentioned in the list in the original post. You can multi-thread with contexts safely, you just have to keep those constraints in mind. Instead of activating and deactivating threads, which I never talked anywhere about, you activate and deactivate contexts. Even if a thread is "inactive" whatever that means, if a context is still active on that thread, it won't be able to be activated anywhere else. You have to consider things from the context's point of view and not the thread's point of view.
I know it is already like this, that is why I've said that the API would stay the same. What I am discussing here is possible implementation changes that could solve the said problems without affecting the API.My suggestion is that the synchronization is done hidden inside SFML, so that the API can stay the same.This is the way it currently is, and if you've read what has already been posted in this thread again, you will see that this leads to problems. And before you say anything else, no, your solution will not solve any of these problems. It will merely create more of them.
Ok, the data depends on the active context, so we have to synchronize data retrieval as well. That could be done by blocking the calling thread until the "drawing thread" retrieves the data, and sharing the return value between threads, but I agree that it is not as clean as it could be.I didn't know we had to synchronize data retrival functions as well. As I've said before, I only know this issue from what I've read here, so if I don't know all of the problems my suggestions will be flawed from the start. How does data retrieval work on OpenGL? Is it thread-safe? Does it support parallel data retrival on multiple threads? Does it use the contexts for that? In what way? I am realy clueless to this point.Data retrieval isn't as complicated as you think, but that still doesn't mean you don't have to give it a bit of thought. It can have many manifestations. The most common and simple one is getting a single state value from the driver. This can be different depending on which context is active when you call the respective function. For things like taking screenshots, it is a bit more complicated. You will have to pass in a correctly sized array so that the GL can write the data you request from it into the array. This is also context dependent, and is a rather slow operation since we are reading data directly from the GPU.
If you heed what I said in the original post in regards to contexts and threads, then yes, it is thread-safe. Yes it supports parallel retrieval on multiple threads, also constrained by the same requirements. Yes it uses contexts, everything in OpenGL uses contexts, didn't you read the original post?If it uses the active context, it can't be used in parallel. Or am I missunderstanding something? If you can't have two different threads retrieving data from the same context at the same time, I wouldn't consider it thread-safe, but that might be bad wording, so I am sorry for the missunderstanding. In the end, we have to synchronize drawing and data retrieval functions to the same context ourselves.
This is worse than I expected... Now I understand that you were aiming to have a separate "rendering thread" for each context that can be used in some way... just so you can omit having to constantly select which one to activate? There are beginners on this forum... that just start out with game development, and after not too long, even they understand that having more threads than necessary is not a good thing. I don't know where you are coming from, but if you think that resorting to creating an excessive number of threads to get anything done is a good idea, I am sorry to have to tell you that you are mistaken. The same is said to beginners as well as advanced developers: Avoid threads while you can. Unless you know exactly why they provide a benefit, you won't gain much from them.Ok then, lets avoid multiple meaningless threads. I'll suggest another solution at the end of the post that doesn't create any aditional thread.
If that is the case, then you must also oppose usage of smart pointers over raw pointers too right? Raw pointers don't create unsolvable issues and have better resource usage than smart pointers, and yet the universal opinion from any established C++ programmer is that you should rarely ever use raw pointers (and certainly not owning ones) in modern C++ code.Using raw pointers directly is much harder than using smart pointer. It is bad practice because unless you pay attention to all of the allocation and freeing of memory, you will create serious problems. Sure, if you don't pay attention to the synchronization of OpenGL operations it will create serious problems, but as long as we manage to take care of those problems internally, it will cease to be bad practice to the final user. If SFML used raw pointers on some internal sections of code, for example, but used them correctly, the user code wouldn't be affected by it in the least. The user wouldn't even see the pointers.
I still fail to see the reason for the drop in performance. Sleeping threads shouldn't affect the performance of the active threads. Anyway, I'll suggest another solution at the end of this post, please take a look.Ok, it is unheard of, but would it work?You tell me... I am not going to go ahead and spend 10s maybe even 100s of hours implementing something I find problematic from the start. From reading what you have proposed, I would say, yeah, it can work, but have fun with your 2 FPS applications. Ultimately, most ideas in software development, no matter how crazy they are, can be implemented. You just have to spend a varying amount of time dealing with the effects you did not anticipate during brainstorming.
From what I did understand from your previous posts, the main drawback was that SFML created a lot of useless contexts so that every operation performs on a different context and we don't have to synchronize anything. I might have missunderstood the issues, but my suggestion was made considering this scenario. Please elucidate me if I am mistaken, but after reading the first post of the thread again this is still what I understood.What are the possible drawbacks? Is the number of threads limited to less than the number of possible contexts on an application? Would multiple sleeping threads (since the threads will be mostly sleeping, except when waken to draw stuff and sleep again) affect the performance of the user's thread? Would those sleeping threads compromise memory in any significant way?I've already reiterated over the drawbacks enough times in the last posts and this one. If you still don't understand them, please read them again. I assume that you are somewhat familiar with threading (and more importantly efficient multi-threading), since you often propose "solutions" to problems that involve them in some way. So can't you just draw your own conclusions? If this is not the case, i.e. you are not experienced in threading, then I highly recommend you refrain from using them in any future solutions you propose anywhere. I don't mean to be offensive, but these solutions don't necessarily make you look good...
That way the context will only be active during the operation, and multiple threads trying to use the same context in parallel would be executed one at a time. What I don't know is: does activation and deactivation of contexts take much time, or is it instantaneous? This solution would be bad if activating and deactivating contexts multiple times would lead to performance issues, but if it is as trivial as changing one state, it won't matter much.This was also a solution I presented to the other team members a while ago. At first glance, it seems like something that might actually work and isn't too complex to implement, but the devil is in the details. I was already working on a prototype of such an implementation, but switched to solving other issues a while ago before it was finished. I guess I could finish it off now and see what it performs like. The performance of these things, and if the drivers play along, is always hard to estimate solely based on the initial design. Often, reality isn't as clean as what the API documentation has you believe. Even when it is finished and seems to work, extensive tests have to be conducted on multiple systems before even considering it for inclusion into SFML.
Another possible variant of the dedicated internal threads suggestion would be to have only one internal thread, and have it doing the OpenGL operations for all of the contexts. If I understood what you've said on the first post, we might gain some performance if driver operations are issued in parallel to different contexts, so this suggestion would remove this possible performance gain, but you make it sound like driver operations are so fast that the gain is trivial. If that is the case, then this solution will be viable.Any time a worker thread does nothing but execute stuff that could have been done in the invoker thread while blocking the invoker thread, you end up with serial execution. This defeats the whole purpose of multi-threading. The fact that contexts can't arbitrarily be passed between threads without some non-trivial synchronization routines does not mean that we keep it in a worker thread just so we don't have to perform those routines.
Personally I don't care how chaotic context management gets with threads, for multithreading isn't for beginners anyway. IMHO context management should be simplest for a single thread.Since you seem to value the simplicity of single threaded context management more, implicit context management.
With these opinions, which option should I vote?