A friend and I are programming a game together in java, and I wrote a new graphics engine specifically for the game, using LWJGL. However, my friend believes that the game would be both better structured and with better performance if all of the drawing occurred in a separate thread. All of the objects to be drawn are contained within a huge tile map. His solution to keep everything thread safe and synchronised well is to make a deep copy of the map to be drawn, and then (in a thread safe way) move the area across to the graphics thread to be drawn. We already have some aspects, such as pathfinding, multithreaded, but he seems determined to do drawing in a separate thread… I just get this gut instinct that it is a bad idea because it goes against the standard game loop…
Am I being narrow minded? or is it it usually more sensible to keep drawing in the same thread as the game loop?
Thank you
(I wasn’t sure whether to post this in the 2d or performance forum, hope this was the right choice)
This does work but… it is very difficult to get working, and in my various tests, rarely achieves more than about 10-20% frame rate increase. And then only if you’ve got a dual-core system: you’ll then find that the performance is slightly worse on a single-core system, which last time I looked was still about 25% of the systems out there in the wild. I’d say don’t bother doing it if I were you and concentrate on getting it working single-threaded.
Nice to see people realize that a computer has more than one core!
The main problem with threading out graphics is that you have to make all OpenGL calls from the same thread, meaning that the graphics thread has to own the OpenGL context. This makes it a little difficult to initialize OpenGL (the Display, e.t.c.) and load textures and shaders, since they also have to be in the same thread. It’s much easier to flip it around and thread out logic instead, since you can call OpenGL commands from the main thread in that case.
There are 2 kinds of thread-safe: Either you add synchronization to a normal solution, or you adapt the solution to not need synchronization in the first place. The second one usually has slightly worse single-core performance, but scales MUCH better with multiple cores, since synchronization costs some performance. Separating graphics and logic is pretty easy, but getting it perfect is pretty hard. The logic thread will read and write, e.g. update the game state, while the rendering will ONLY read information to draw stuff. Not much synchronization should be needed, but there is a big problem: The state may change during drawing, which may surprise the rendering thread. Some objects may have data from the last update while some objects have been updated. This is okay for a relatively simple 2D game, but in 3D, this can produce seams in the world!
I made a small library for threading games. In it you’re meant to setup Task objects which perform different tasks. A Task has a list of other Tasks that needs to have been completed before it’s allowed to be run. The Tasks are compiled into a TaskTree which can be run from a GameExecutor. This allows pretty complex threading to be very easily implemented.
You can make two Tasks run at the same time by having two Tasks that do not require each other. A multithreaded GameExecutor will put these on different threads. You’re not supposed to have any manual synchronization inside Tasks.
You can also make Tasks themselves multi-threaded by using a SplitTask. For example this allows you to multithread movement updating by updating every other object from two different threads.
My engine is multithreaded. I have a game engine thread, the rendering thread and the network threads. For a game that has AI there is the AI threads.
My reason for doing was to separate the screen frame rate from the game turn rate. Turns out that it kinda doesn’t work well without a lot of interpolation code on the rendering side. However this still makes the code much cleaner. Most of the work is still rendering so there is not really a performance increase on a mutlicore system in this case.
For synchronization, the engine gives out game state snapshots to the renderer with a thread safe queue from java.util.concurrent. The controller (aka gui in the renderer) sends command objects to the engine which again just uses a thread safe queue. The map, since it does not change, is shared without any synchronization.
Keeping all the opengl code in a single thread was easy enough. You can always use Display.makeCurrent() otherwise.
I find thread programing reasonably easy if you keep the threads coarse and the communication between them simple. Note also that opengl drivers may do things in the background for you too.
But princec does have a point… get it working first… get it playable.
Threading should be one of the last things you implement in the game, but you should still be coding with concurrency in mind if you plan on implementing it later. I am making a strategy game, which means that the CPU is a huge bottleneck in AI, line of sight, e.t.c, meaning that threading is pretty much necessary for large maps with many units. I expect an almost linear increase in performance for the parts I plan to multithread using the threading library I made.
Thanks for the info, I think i will follow this advice.
Thanks for the info, I’ll take a look at that threading example you made
(although we have already implemented a lot of threading, so I will only read it for advice, thanks anyway ;))
Yeah, I think we’ll persue this route, thanks
I’m not sure using interpolation would be very effective for our game, there is a lot of movement going on, and it’s tile based, so I think it would be fairly obvious if a character overshot and had to jerk back in another direction…
We are making a strategy game also, but I feel it is always easier to multithread code while you know it well. If you code it thinking of concurrency anyway, then usually it won’t take long to actually make it concurrent, I feel it is more useful to make it concurrent at the time of writing, really.
Once again, thank you all very much for all of the assistance
My point was not clear about interpolation. It was a royal PITA and i dropped it. I need the engine to run as fast or faster than the frame rate for now. Getting interpolation to work is not as easy as it looks.
This is the problem I always have when thinking about decoupling logic and rendering. To not get hideous threading issues you need to take either one interpolation-aware snapshot, or two snapshots and somehow interpolate between them. Now maybe other people’s games are different but even with a very simple game you could have hundreds of different entities, items, etc. all moving around with position/velocity/angle. Now every single game logic class has to be interpolation-aware, adding extra tedium and work when writing any gameplay code.
It seems like the response is often ‘just clone the world state and interpolate’ as if that’s the easiest thing in the world (not trying to pick on delt0r here, since he said it was a massive PITA). Not to mention that cloning the world is decidedly non-trivial in terms of cpu and memory usage.
I have never seen a non-trivial game doing the clone-and-interpolate method, certainly never in a console game where the memory usage would be prohibitive. Everything I’ve seen takes a more pragmatic view by running (say) animation at a lower interval (like at 10fps instead of 60fps) or possibly offloading the heavy computation to a thread (ai) but from the purposes of the game loop it still looks like it’s being updated and rendering at full rate.
Would love to hear from someone who’s done a non-trivial game with the clone-and-interpolate method, and how they solved the above problems.
I don’t interpolate. I just use the latest snapshot. If they are fast enough it works fine.
However i did manage to get interpolation working. I will put it back in too later if needed. The main reason i wanted it was because i didn’t want 60 network “frames” per second. But jittery networks are a way of life, so i wanted to not just interpolate, but adaptively with changing update rate in a way that doesn’t look bad. The trick was to always be 2 frames behind the game engine, that is i can interpolate between frame n to n+1, and i adaptively change the speed so that by the time i get to frame n+1 the n+2 frame is available. I even used a PID controller to do it, well i drooped the P.
This however adds quite a bit of lag. By the time the frame rate is fast enough to get the lag down, it was fast enough to not bother with interpolation. So i just cut it out. If i need to add it later because of networking, i will add it at the engine level, not the view level. This keeps it all in one place.
And i am derailing another thread :persecutioncomplex:
You don’t have to interpolate everything. Just interpolating position/movement is pretty much enough for the game to look smooth. If you want more interpolation, just add it as you go. It’s not that hard to integrate, just tedious.