[SOLVED] Managing Contexts

Started by aeonios, December 14, 2015, 16:49:58

Previous topic - Next topic

aeonios

I'm currently working on building a 2D graphics library for java because as far as I can find there isn't one (and Graphics2d doesn't count, either). I had originally intended to use slick2D but unfortunately that didn't do what I needed it to (well, it sort of does, and sort of not) and did some things that I couldn't have it doing so I ended up forking out all of the graphics related code into a new library. It was using a 2.x version of lwjgl which also had some major drawbacks so I've been working on porting it to the latest stable.

Mind you I know very little about openGL which makes this all the more difficult. :P

Anyway I added an SWindow class to wrap GLFW's window functions and have been using that (perhaps incorrectly) to get a context and capabilities. Unfortunately it throws a "no capabilities" state exception whenever FBOGraphics tries to unbind an EXTFramebufferObject. I have a strong suspicion that I'm doing it horribly wrong, but I don't really understand it well enough to know the difference between what I want it to do and what it's actually doing. Note that I'm only using a single thread and always initialize glfw and create a new SWindow object before doing anything else with graphics. AFAIK only the graphics objects throw GL-related exceptions anyway since images are loaded into non-GL buffers and only transferred when you get a graphics from them.

EDIT:

Well, after fighting with it for a while I've concluded that slick is a heap of bitrotten interface ridden voodoo spaghetti. At least a lot of the gl wrapper code is. I'm still not sure why I was getting that error but I decided it would be easier to burn it in a fire than to try to figure out how that mess worked. So far I've managed to figure out quite a bit of GL11 and glfw.

Cornix

Slick is outdated and does not have a very good reputation. At least all the people I have ever talked to had nothing positive to say about it. However, there is LibGDX which many people recommend. LibGDX is a huge library that simplifies the process of developing games. It hides all the low level OpenGL / OpenAL stuff away and works across many platforms.

aeonios

I looked at LibGDX but in no way does it do anything I need. All I needed was to add blend some stupid circles and lines onto an FBO, and maybe composite a few such generated images together and draw them to a window. If Graphics2D did that I'd be using it, except that drawing circles with a custom add compositor is pathologically slow. As in, a hundred 2D circles or so and it drags a 3D game down to 1fps.

Cornix

How does LibGDX not do that? I am pretty sure LibGDX allows you to draw lines and circles and use any Blend-Mode you like (even write custom shaders). I am not entirely sure it exposes FBO functionality but I would be surprised if it doesnt.

aeonios

For all I know it might, but I don't shaders and I don't feel like trying to figure out libgdx's API for Graphics2D level functionality. :| I think it does have a simple enough interface for buffers, but its interface wrt raw geometry seems pretty complex. It also seems to use GLES by default when I'm targeting desktop systems. I'm not exactly writing a game either, but an AI for one, which has rather different requirements and concerns.

aeonios

Well, I have my basic library code working now, but getting it to run in the context of my application has led to new issues.

Basically, I'm writing an AI for a game that provides a JavaAI interface. The interface calls the AI to update its state through a number of different events starting with init(), and all of my drawing code runs during update(). The AI only sort-of has an interface for debugging, but it uses images as a form of database with GL as an accelerator for writing to it.

The problem is that since it's called from events (even though there's only one thread), the GL context created during init is not reachable from update. I tried unbinding the context at the end of init via
glfwMakeContextCurrent(NULL);

to make it available later, but for whatever reason that causes the game to crash. I also tried setting
glfwWindowHint(GLFW_CONTEXT_RELEASE_BEHAVIOR, GLFW_RELEASE_BEHAVIOR_NONE);

but that didn't stop it from crashing.

I'm not sure what to do since there are a lot of restrictions and the usual method of handling this sort of thing has failed.

Kai

Are you absolutely and 100% sure that there is really ONLY one thread?
If you are using for example a Java UI framework such as Swing, then in addition to your application's "main" thread there is also the AWT Event Thread processing window messages and calling into keyboard/mouse/etc event callbacks/listeners, even if you never did new Thread() in your own code.
You can check which thread invokes what by adding a Java breakpoint to the relevant method/line and running the JVM in debug mode (i.e. attach a remote debugger to it). All IDEs support this natively.
Then, when the breakpoint is hit, you can inspect the executing thread.
General advice though: Don't call GL methods from some other event thread when you have the main thread running which also calls GL methods. Use shared state to communicate between both threads or synchronize both threads accordingly if you absolutely must call GL methods in the event thread.

aeonios

I'm not using anything outside of glfw for ui, and I checked using java.lang.Thread.activeCount() at several points. There's nothing that runs more than one thread, it's just a peculiarity of the state that occurs when code is called via an event.

Cornix

You could give your threads names and then print out the name of your thread(s) when (it/they) perform your OpenGL calls. It might also be possible that you call something in the wrong order and you try to call a gl function before you have initialized your context. Try some dynamic program analysis by using a debugger (or similar software). It will be much more accurate then guessing.

Kai

Please post a Minimal Working Example to reproduce your issue. Otherwise no one can help you.
If you properly called glfwMakeContextCurrent() and after that GL.createCapabilities() then every GL call made afterwards will work without saying there not being a current context.
Otherwise you either explicitly detached the GL context from the thread or used another thread. There is no other reason.

aeonios

a 'minimal' example for this would be extremely difficult.

Whether there is or isn't a separate thread isn't really important here, just that it behaves as though there were.

AFAIK in order to pass a context from one thread to another first you have to unbind it from the first thread then make it current in the second thread. I tried that but it causes a crash (which apparently comes from some sort of GL conflict with the game and is not intrinsic to my code or lwjgl, which were not the things that crashed). My program also does not have a main() loop, since it's subordinate to the game framework. I'm not sure if it's possible to give it a main loop since that would probably interfere with responding to events.

I'm looking for a possible alternative. Creating a new window every time update() is called (and destroying it at the end of the call) would probably work, but that wouldn't allow me to run a persistent debugging window.  I'm not sure if that would avoid the same sort of crash either. It may be necessary to report the crash game-side if that's a real issue that needs to be fixed and/or if I can't find any way around it.

Kai

If your framework is being used by a main program/game/application then ask the designer of that game what the contract/interface between it and any subordinate frameworks/plugins/libraries like yours is, especially with regard to lifecycle and threading. Is there some kind of "init" event in the lifecycle of the application that you hook into and is it being called by the same thread that also calls those "events?"
In this regard, doing a MWE is actually in your own interest in order to find where you currently seem to have a misunderstanding of OpenGL or more likely the main game/application and its interface to your library regarding lifecycle.

aeonios

Hmm.. well I decided just to mark this as solved. I doubt they anticipated an AI using openGL for anything, but I reported the issue so it should get figured out one way or the other. I did try some things but with no result, and it doesn't look like something I can fix myself.