Welcome, Guest. Please login or register. Did you miss your activation email?

Poll

Do you prefer SFML to manage contexts implicitly, or explicitly? If you are about to vote for option 3 or 4, please do so before reading the post, thank you.

Explicitly, I want more control over how they are used.
Implicitly, I don't want to have to deal with them myself.
I've heard of them before, but what do they do and why do I need them? I want to learn.
I've never heard of these contexts before, but I am willing to learn about them.
Keep these context things away from me! I chose SFML for a reason...
I really don't care. (Please only select this option if you have read the post and given this a bit of thought.)

Author Topic: SFML Context Management  (Read 20860 times)

0 Members and 1 Guest are viewing this topic.

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
SFML Context Management
« on: October 02, 2014, 04:06:50 am »
Hello awesome SFML forum! :D

Today, I (We? Can't speak for the other team members..) approach all of you to ask for your opinion on the matter of:

SFML Context Management

This has been an issue that I have personally been involved in for a long time, and I can imagine many others, including Laurent himself of course, have expressed their concern in regards to this matter time and again.

With the SFML 3 vision thread up in full swing for just over 5 months, there is no doubt that we are going to start work on SFML 3 sooner or later.

As you all know one of the biggest uses of SFML, is in the area of 2D graphics. To realize this, SFML builds on top of the cross-platform graphics API OpenGL. As with any hardware accelerated API, there needs to be some form handle to identify the accelerator device in question, whether it is really the physical device or a virtual device that is emulated by the driver. DirectX names their handles, devices, fittingly, and OpenGL decided to name their handles contexts. OpenGL has had a long history, much longer than DirectX, and needless to say, the concept of contexts as a container for GL state has existed since the beginnings of OpenGL.

For those familiar with OpenGL, you know that calls to the OpenGL API will only have an effect if a context is currently active, to keep it simple for now. Any state modifying calls will modify the state of the currently active context and no other. Since OpenGL used to do most of its work via bindings (i.e. state variables), understanding how contexts work is essential if you plan on using multiple of them, and that is where the difficulties arise.

There are a certain set of constraints that have to be met when dealing with contexts. Many of them are probably the result of operating system constraints from the time when the first specifications were written, but they haven't changed much since then. I will try to list most of the important ones here so that you can understand what I mention later better.
  • Contexts are containers for OpenGL objects, identifiers to resources that live somewhere, either in the driver or on the GPU itself.
  • Contexts are containers for OpenGL state. OpenGL can be seen as one huge state machine, and you manipulate this state to alter what you see on your screen.
  • OpenGL operations operate either on state, or objects. If the container (i.e. context) for these does not exist, naturally, OpenGL operations will have no effect.
  • Almost all OpenGL objects can be shared between contexts. This simply means that they share the same identifier space, meaning that an identifier generated in one context can be used in another. In previous versions of OpenGL, one did not even have to generate objects and could manage the identifiers without the help of the driver. This however has been deprecated and will cause an error in newer OpenGL. The most prominent examples of objects that cannot be shared between contexts are framebuffer objects, the underlying object of an sf::RenderTexture and vertex array objects, containers for vertex attribute binding state in modern OpenGL.
  • Context resource sharing works on a peer-to-peer basis. Sharing is associative. Once contexts are shared with any context that is part of a chain of other contexts, it cannot be "unshared".
  • Every context has its own default framebuffer, basically a surface on which all draw operations have an effect. This cannot be suppressed, even if one does not intend on ever drawing to that framebuffer.
  • Contexts can be activated and deactivated. The currently active context is the one that OpenGL operations have an effect on.
  • Contexts can only be activated in a single thread at a time. It is an error to activate a context in a different thread than one that it is currently already activated in. In order to switch the thread in which a context is active in, the previous thread has to deactivate it and only after that has been done can the new thread activate it.
  • What follows from the previous points is that only a single context can be active in a thread at any given time. Activating another context than the one already active will automatically deactivate the currently active one first. Multiple contexts can simultaneously be active, but each in their respective threads. Unless you know that your application causes a lot of work in the driver (not on the GPU!) and that you have a multi-threaded driver, splitting OpenGL work up among multiple contexts in multiple threads will provide absolutely no gain in regards to OpenGL performance. Developers who know how to get a hold of that information will probably also understand how to exploit multi-threaded GL, but most of the time, this is simply not the case. With future OpenGL versions, reduction of driver overhead is also part of the plan, so multi-threaded OpenGL usage will keep losing significance as well.

SFML makes extensive use of OpenGL for drawing throughout its graphics module, and marginal use of OpenGL in its window module in order to provide context support for developers who aim to use OpenGL directly.

The technical details come now.

Due to historical reasons, Laurent chose to have a single context that serves no other purpose than to be shared with any context that is created after it. In SFML code, this context is referred to as the "shared context". The shared context is the first context to be created in an SFML application, due to the fact that any future contexts have to be shared with it. It is created as part of the global GL context initialization which happens as soon as the first sf::GlResource is created. It relies on reference counting in order to track how many objects there are that still rely on having an active context. Once the last sf::GlResource is destroyed, the global GL context cleanup is performed, which gets rid of the shared context as well. In addition to that, the cleanup function also gets rid of all "internal contexts".

SFML sets up a sort of "invariant" that states that as soon as a sf::GlResource has to perform any operation within any thread that thread will have to constantly have a context active at all times, even when not required. Maybe this was done for performance reasons? I do not know (only Laurent knows :P), and the difference was barely measurable in my tests. As opposed to "standard practice" of deactivating contexts when required, SFML "deactivates" contexts on the current thread by activating a so called "internal context", a thread local context that makes sure that the invariant of having a context active at all times is upheld. These internal contexts are created the first time they are required (i.e. a context was activated and requested to deactivate) and due to the way the context management works, they cannot be destroyed until global cleanup, which typically happens when the application closes. This results in what is now known as the "context leak" that has been discussed on the forum and tracker often enough. Applications spawning temporary threads to perform sfml-graphics operations will notice a constant rise in memory usage due to this, and at some point, the driver will also give up in trying to manage the excessive number of contexts.

Are these internal contexts ever used when (and if) they are active? Not very often in typical code. If an application doesn't make use of sfml-graphics in secondary threads without an explicit context object and never explicitly calls .setActive(false) from within the main thread (the one that deals with the main window) or creates sfml-graphics objects before the main window is created, it will likely never be used. Nonetheless, it is created, all the time. If you are proficient in OpenGL debugging tools, you will notice that even the simplest SFML application, such as those found in the beginner tutorials will end up creating 3 OpenGL contexts, although the shared context is unnecessary (according to my tests) and the internal context is rarely ever used.

Additionally, because framebuffer objects cannot be shared between contexts as stated above, in order for SFML to guarantee that a sf::RenderTexture can be used in any thread after it is created, it has to contain its own context that is activated solely when something is to be done on the sf::RenderTexture and deactivated thereafter. This means that in a single-threaded application with a "large" number of sf::RenderTextures, the same number of additional contexts will have to be created, one for each sf::RenderTexture. The alternative implementation of sf::RenderTexture using a secondary context's default framebuffer on systems that don't support framebuffer objects is more justified, but the systems that cause this to be the case are getting less and less common.

The reasoning behind the current design stems from the fact that SFML tries to hide context management from its users. The assumption is that context management shouldn't be something that beginners have to struggle with when they already have so much to learn. This is true, and maybe it should be something that is kept for understanding at a later time, but I personally find that learning that a context has to be active in order to play with sfml-graphics is something that shouldn't be too hard to grasp. The problem is that I, Laurent and many others already have a lot of experience with graphics programming, so what might seem easy for us might seem like a nightmare for beginners. Conversely, what might seem like a boon to beginners is a nightmare to advanced users (e.g. threaded sfml-graphics).

SFML 3 will probably bring with it a lot of changes, and Laurent has already proposed his ideas on separating the sf::RenderTarget concept from the window and offscreen rendering surface objects (currently sf::RenderTexture). Conceptually, a sf::RenderTarget is nothing other than a context that is used to target a surface to render to, so in that respect a change in regards to context management wouldn't be as drastic as some might expect.

I would have provided mockup examples of what explicit context management might look like, but I decided against it since it is only one of many possible ways of exposing it through the API and I don't want to influence the outcome of the poll because of that.

We really need community feedback on this matter. Should SFML make context management more explicit? Or do you think that it should stay implicit since this is what makes SFML different from (and better than?) all other multimedia libraries?

Please try to be honest and give the poll a bit of thought before voting. In the case you retrospectively change your mind, please try to factor in the gut feeling you had when you voted previously. We want the API to feel good and easy to use, yet powerful at the same time, and there is no better way to judge the "feel" of the API than relying on your gut feeling. Also, since I hope to get a representative opinion on this matter, it is important to motivate as many of SFML's users to vote as possible, especially those that don't visit the forum very often. SFML will always try to be beginner friendly and thus their opinions are worth just as much (if not more) than those of us who have been using SFML for years, and yet they are probably the ones who are the hardest to get a hold of for these kinds of polls.

For those who are afraid/shy of exposing yourself, keep in mind that voting is anonymous (posting is not mandatory), and only those with database access (i.e. those who really don't care ;D) can check what you voted for, if they even invest the amount of effort required to do that.

I would be happy for your feedback on this matter :).
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Tex Killer

  • Full Member
  • ***
  • Posts: 242
    • View Profile
Re: SFML Context Management
« Reply #1 on: October 02, 2014, 05:18:58 am »
From what I could understand from your post, apart from that "context leak" issue, I see no reason at all to even consider those contexts. Maybe SFML's internal code could be improved to remove those useless contexts as you've said, but why would I want to manually use them? What could I do with direct access to them that I can't do now?

Aside from that, what about DirectX rendering support? If it is implemented (and I hope it gets into SFML3), won't contexts only exist natively on OpenGL supported devices? In my oppinion, DirectX support is much more appealing to me than those contexts (I might change my mind depending on your answers to my previous paragraph, but I find it unlikely).

Ruckamongus

  • Jr. Member
  • **
  • Posts: 70
    • View Profile
Re: SFML Context Management
« Reply #2 on: October 02, 2014, 05:55:29 am »
I have to agree with Tex Killer; I was attracted to SFML because of its hardware accelerated graphics and abstraction over the nasty OpenGL stuff. I feel that SFML should continue to manage contexts internally, but if you're considering an internal rewrite of the context management perhaps it's time to think about rendering backend abstraction as well. It would be a massive amount of work I'm sure, but being able to choose a renderer (OpenGL, DirectX, Apple's Metal?, etc) could attract a wider audience. Also this may allow development on different platforms to be easier; Android with ES, Apple with Metal (have they concluded if they're dropping OpenGL support fully in the future?), Windows with DirectX, OpenGL with everything else.

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.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10930
    • View Profile
    • development blog
    • Email
Re: SFML Context Management
« Reply #3 on: October 02, 2014, 08:35:59 am »
I think it's important to state, that this thread shouldn't turn out into yet another "rendering backend" discussions, we already had that on the SFML 3 thread, so please don't go into any further - mentioning it as argument for context management is a valid point, but please no "I want feature X more than Y".

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.

I don't have experience with OpenGL, but talking to different people and understanding as many of the pros and cons, it seems that the current system is not optimal. Until now it more or less successfully hide the context systems from the casual user (I'm sure many didn't even know that they existed). But at the same time it makes the life of the advanced users a nightmare and I've seen posts here and there which were surprised about SFML's strangely high number of contexts and some even switched to SDL since they couldn't handle contexts explicitly.

Thus while SFML's audience consists currently mostly of new beginners, I'd really like to see SFML being used in a lot of advanced code bases as well. Context management should in my opinion be explicit, however if somehow possible it would be nice, if when operating within one thread on one window (most basic use cases of SFML), one would have to deal with contexts.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

select_this

  • Full Member
  • ***
  • Posts: 130
  • Current mood: just ate a pinecone
    • View Profile
    • darrenferrie.com
Re: SFML Context Management
« Reply #4 on: October 02, 2014, 09:58:33 am »
Personally I'm in favour of explicit context management being at least possible, if not the default. Perhaps there could be some mechanism to decouple SFML's concepts from the contexts.

I'd be wary about ditching SFML's context management entirely; the forum is already filled with tons of posts about textures not being drawn correctly due to scoping issues, as an example, so I can imagine the flood of angst that will be received should SFML stop behaving in a way that people have come to expect ;)
Follow me on Twitter, why don'tcha? @select_this

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: SFML Context Management
« Reply #5 on: October 02, 2014, 10:19:58 am »
Before thinking about what we would like to do, we should focus on what we can do. binary1248, your tests showed that the limitations the current code works around no longer apply. 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 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?
Laurent Gomila - SFML developer

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: SFML Context Management
« Reply #6 on: October 02, 2014, 10:43:30 am »
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 guess writing simple test cases isn't too hard, but considering that SFML normally takes care of the cross-platform part, in this scenario we would have to write different code to test the same feature for different platforms, and that can become... quite tedious :P.

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.

I've also experimented in the past with cutting down the number of contexts SFML internally uses and I would have had a working implementation if I gave it a bit more effort, but that branch also assumed that many of the things you also mentioned back then that had to be tested were simply given. I recently browsed over the changes again before starting this thread, because, contrary to what people might think of me, while I would prefer having explicit control of contexts, I also have a somewhat working solution if it is to stay implicit as well. I guess I can finish up on it when I next find time and provide it to SFML users for testing. This would also alleviate the need to write individual tests as described above.

Of course, this should not prevent people from taking part in this poll :P.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Nexus

  • Moderator
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: SFML Context Management
« Reply #7 on: October 02, 2014, 10:49:10 am »
binary1248, thanks a lot for the detailed and insightful explanation, it really helped me understand some important details.

I have a question similar to Laurent's: you present implicit and explicit context management as alternatives. What limitations would implicit management imply, the same as currently? Or, is implicit management even a true option when we want to defeat the context leak and reduce the number of unused contexts? I'm not sure whether such designs are still being investigated, or whether there is a fundamental constraint preventing them.
Edit: Ah, I saw you referred to that point in your last reply.

And as I've understood the issue, it will be very difficult to provide an API that handles things implicitly for most users, but allows more control for users with specific requirements, right?
« Last Edit: October 02, 2014, 10:54:00 am by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: SFML Context Management
« Reply #8 on: October 02, 2014, 11:25:00 am »
Currently, this only really applies to users of sfml-graphics. OpenGL programmers who only use sfml-window (like me) are unaffected by context management, because well... context management is only done when sfml-graphics resources request that contexts are active to perform any OpenGL operation.

The reason why it might also affect people like me, is because, simply put: I am lazy :P. I use sf::Texture a lot instead of manually managing OpenGL texture objects myself, and the same with sf::Shader. They fit my needs perfectly most of the time, but they also bring with them the whole context management issue. The "issue" with the shared context also affects people who don't use sfml-graphics in any way as well, since sf::Context is also a sf::GlResource, and will cause the whole global initialization/cleanup like any other sf::GlResource.

Take this really simple example:
#include <SFML/Window.hpp>
#include <SFML/OpenGL.hpp>

int main()
{
    sf::Window window(sf::VideoMode(200, 200), "Test");

    while (window.isOpen())
    {
        sf::Event event;

        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }

        glClear(GL_COLOR_BUFFER_BIT);
        window.display();
    }
}
This is a barebones OpenGL skeleton that every OpenGL application will start out with. How many contexts do you think are created just for these 21 lines of code, not even using sfml-graphics?

1? Nope...
2? Wrong again...
3...

When the sf::Window is created, it causes global context initialization since it is a sf::GlResource. This in turn creates the shared context, and in the current implementation, the shared context is immediately deactivated after it is created, which, as I described in the original post, is done by activating the internal context (which is created the first time it is required). After that is done, the actual context that is used for the rest of the application is created by the window.

This means that no matter how you try to do things, there is no way to use SFML for OpenGL without having to create at least 3 contexts, and I can understand why some more experienced OpenGL coders might already seek greener pastures when they discover this.

It is probably easier to solve this issue first before tackling the whole sfml-graphics context management, since we can assume that in this use case the user really only wants a single context. But in the end, I think any fundamental changes we make to either this use case or the sfml-graphics use case will affect the other anyway. In that sense, I don't think it makes sense to provide 2 different paths (one simple and one advanced) for users to choose from. 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.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Ruckamongus

  • Jr. Member
  • **
  • Posts: 70
    • View Profile
Re: SFML Context Management
« Reply #9 on: October 02, 2014, 12:42:25 pm »
binary1248, I'm still not fully grasping the contexts fully. Are you saying that every sf::GlResource will not be freed until the termination of the program? 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 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.

Wouldn't that mean sfml-graphics would depend on sfml-window? That seems counterintuitive to the goal of reducing coupling?

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: SFML Context Management
« Reply #10 on: October 02, 2014, 01:20:43 pm »
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.

Quote
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.

Ideally, sfml-graphics shouldn't have to be worried about the underlying graphics library or objects in use. It would rely on a module that serves no other purpose than to generalize and simplify library specifics so that people who use that library (and not sfml-graphics) would have the same access to those objects that sfml-graphics provides now, with as much flexibility as e.g. raw OpenGL code would provide them as well.

When I mentioned coupling, I meant bidirectional coupling. Certain concepts, such as sf::GlResource are used almost exclusively by sfml-graphics, and yet are part of sfml-window, probably because sf::Window and sf::Context were designed to be sf::GlResources themselves, although I personally don't consider them to fit into that idea as well as the other objects do. Extension loading code should technically also be part of the sfml-window module, since that module occasionally has to load extensions itself as well. I actually ended up doing this in gl_dev, since it made sense to me. The glLoadGen implementations that are still part of sfml-graphics no longer contain operating system specific code. That was moved into sfml-window so it could be reused by modules that are to be built on top of it.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

wintertime

  • Sr. Member
  • ****
  • Posts: 255
    • View Profile
Re: SFML Context Management
« Reply #11 on: October 02, 2014, 03:09:45 pm »
I already said somewhere that I'm in favor of ripping out all those hidden contexts.

For a typical single threaded SFML program that beginners and intermediates produce it would be just:
- create (and maybe activate) the window before using any other object from the graphics part
- keep the window object alive (and activated) until you stop using any objects from the graphics part
(- it may or may not be needed for the user to create a context object after that and also keep it alive, depending on if windows continue to contain one, which only depends on how SFML implementers want it done)

For an advanced multithreaded program it would just require additionally to create a context object on each thread that needs to access graphics and keep that alive and active there until the thread is stopped or does not need to access graphics anymore.
Everything else could still be handled internally by SFML although it does not create any hidden contexts anymore.

Therefore, people would not need to be afraid of explicit context management, because it comes down to very simple requirements on the user, which all people are already following with Textures that need to stay alive while they are used for a Sprite and fonts that need to stay alive while used for text. ;)

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: SFML Context Management
« Reply #12 on: October 02, 2014, 11:52:17 pm »
Well, I've never written a line of OpenGL code, and despite all my lurking on the forum reading threads like this I still don't really understand this context stuff, so hopefully I count as a "beginner".

Personally I don't think I can separate the question "Should SFML context management be more explicit?" from the question "What would the concrete API changes be?"  If it was impossible to expose manual context management without making the API as off-putting as raw OpenGL, then I'd be firmly against it.  But if it was possible to expose explicit context management with a minor change such as requiring an extra argument to all your RenderTargets (which shouldn't be all that numerous), then I'd be all for it.  That said, I'm under the (possibly naive) impression that the latter is far more likely.

As a semi-competent noob, the thing I really like about SFML is not that it's simple: it's that it lets you choose exactly how simple or complicated each part of your app should be.  In C++, you only pay (in performance) for what you use.  In SFML, things are only complicated if you want to do something complicated with them.  As a simple example, if you want to do 3D graphics, SFML lets you go "down" to raw OpenGL for that without complicating the window, audio, and networking APIs in the slightest.  Context management is one of the few things that does not currently work this way, and even if I never need it, that should change somehow.

But even after reading all of the above discussion (and many past threads about this), I still have very little confidence that I understand this context stuff.  So, here are a bunch of high-level claims I think are true about SFML and context managment, but probably aren't.  How close am I?
Quote
  • 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.
« Last Edit: October 02, 2014, 11:54:50 pm by Ixrec »

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: SFML Context Management
« Reply #13 on: October 03, 2014, 01:28:30 am »
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 anyway
For 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.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Tex Killer

  • Full Member
  • ***
  • Posts: 242
    • View Profile
Re: SFML Context Management
« Reply #14 on: October 03, 2014, 02:29:01 am »
Ok, since you seem to know contexts in detail, can you confirm those points for me as well?

• In order to have a render target (Window or RenderTexture, for example) you must have a context bound to that target.
• Every context is bound to a render target, even if to a "virtual" and useless one.
• 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 target.

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.

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.

 

anything