Jump to content
  • Advertisement
Sign in to follow this  
JekasG

Design Ideas for a Multi-Threaded Game Engine

This topic is 536 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Sup guys . .

 

I'm scratching my head on this particular topic for quite some time already.

I've been reading several books and watching GDC's on this particular topic aswell.

But I just can't seem to wrap my head around it.

 

I want to write an engine which fulfill several things.

  • Task-Based Multi-Threaded System
  • Network System (Possibly Multi-Threaded aswell)
  • OpenGL Rendering System (Possibly Multi-Threaded aswell)

The core of the system must fulfill these things.

But this is easier said than done.

 

There are many problems that I can think of which bothers me as I know very little of it.

In fact, this entire project thing. I know very little of it.

 

  • Memory (How is it handled in this complex engine)
  • How do we make everything an abstract class of Task ?
  • Is it possible to Multi-Thread OpenGL calls? Is so . . How?

 

These are just some of the larger doubts which I have.

If someone could provide me with some insights and design patterns. That would be awesome!

 

Thank you in advance.

Edited by JekasG

Share this post


Link to post
Share on other sites
Advertisement

Moving to Game Programming. (EDIT: Somehow it also ended up locked. Since I can't see a problem with the thread, I unlocked it. Hopefully not treading on any other moderator's toes here.)

 

My first suggestion would be - don't approach this as "multithread all the things". Either (a) multithread a system at a time, or (b) create a generic job system which most things can then use.

 

Some of your questions are bit odd though, because they don't seem to directly relate to the core issue.

 

"memory (How is it handled in this complex engine)" - memory doesn't necessarily require any special treatment. You will want to avoid reading and writing to the same object in different threads where possible, and use correct synchronisation where it is not. There are certainly interesting ways you could handle memory management differently in a heavily threaded engine but that should be low on your list of priorities.

 

"How do we make everything an abstract class?" - how is that relevant?

Edited by Kylotan

Share this post


Link to post
Share on other sites

Moving to Game Programming. (EDIT: Somehow it also ended up locked. Since I can't see a problem with the thread, I unlocked it. Hopefully not treading on any other moderator's toes here.)

 

My first suggestion would be - don't approach this as "multithread all the things". Either (a) multithread a system at a time, or (b) create a generic job system which most things can then use.

 

Some of your questions are bit odd though, because they don't seem to directly relate to the core issue.

 

"memory (How is it handled in this complex engine)" - memory doesn't necessarily require any special treatment. You will want to avoid reading and writing to the same object in different threads where possible, and use correct synchronisation where it is not. There are certainly interesting ways you could handle memory management differently in a heavily threaded engine but that should be low on your list of priorities.

 

"How do we make everything an abstract class?" - how is that relevant?

 

Sorry . . I updated my question. What I meant was.
 

How do we make everything an abstract class of Task.

From this, I mean.

For the Task System we would need a queue of Tasks.

For everything that we need to do. We make it inherit from Task.

Add those tasks that we need to do into the Task Queue and process it.

But the problem is. How do we make everything as a Task?

Share this post


Link to post
Share on other sites

At the lowest level this is pretty trivial. A task could be as simple as a class that just has an abstract "Run()" method, which your task implements.

Share this post


Link to post
Share on other sites

Think of it as a pipeline where the game turn/time-increment gets passed through different phases and work is started on the next time increment once the current one is completed- all to keep as many CPUs/cores doing as much useful work as possible.   Some like the network threat are also for timely responses.  Another is 'divide and conquer' -  spliting up a processing type to be on multiple cores to speed that processing's completion.   Some processing like AI doesnt have to be restricted to a framerate/render schedule and can use longer independant processing to reach the decisions then used by whatever entities take action in the game.

 

How the data sets get handed off between the threads is a key part of the whole system  (data locks a key subject to understand)

 

The rule usually is one thread per core to avoid processing jobs fighting each other.  breaking all the processing 'tasks' up so they run at the right time and balancing the work splitup so one chokepoint part isnt causing everything to wait for it  to complete.

 

CPU affinity is a term you might be interested in looking up.

Share this post


Link to post
Share on other sites

You'll probably also want to think of overall design goals. For example, do you want lowest latency from input to display on screen, or maximum throughput but with several frame delay from input to display?

 

In the low latency case, you do game updates with N threads, physics collision with N threads, and rendering with N threads, one after the other. Or, you can run game updates, physics, and rendering all at the same time, but you need to store state per thread so you don't have to synchronize except for the state at the end of the frame. 

 

I'd recommend using knowledge about what the game engine will do to make a more specific task system, than something overly generic. 

 

As for OpenGL, you have to make all your draw calls serially from a single thread (you can use multiple, but you'd have to synchronize and switch contexts). You might look into Vulcan/DX12 (or DX11) so that you can parallelize building command buffers.

Share this post


Link to post
Share on other sites

But the problem is. How do we make everything as a Task?
You seem to be doing things backwards. You first find a solution ("make everything threaded", "make everything a task"), and then try to find how the problem you're solving fits in the solution.

 

I would suggest you try it the other way around. Start from the problem, and don't jump to a solution, but consider what it has to do, what services should it provide. Once you have a clear picture of that, decide how to do that. Perhaps you'll still make everything a task, but at least you clearly know at that time it will give the desired result.

Share this post


Link to post
Share on other sites
How do we make everything an abstract class of Task ?

 

you're assuming everything will inherit from task.   never assume. do your research. "get smart on this stuff" as my boss at WPAFB used to say.  figure it out, then code.

 

As dukas points out, there is parallelism (running render in parallel), and "go wide" (parcel out jobs) as possible approaches. or even a combo of both perhaps if you have the cores.

 

I know that Hodgman knows a lot about prallelism, so you're getting it more or less straight from the horse's mouth there.  

 

Figure out what it should do. figure out the variables and functions required. then group related stuff into classes and see what you come up with. this is "bottom up design".

 

top down design is awesome if you know exactly what you need. you just define the API, then fill in the blanks.  if you're unsure, your first stab at top down design seldom turns out to be a perfect guess.  

 

sometimes you have to do a little of both. think about what you need at the bottom end (vars and functions/methods). then think about what you need at the top end API (the simple clean API you want to code to) . eventually meet in the middle. this is top doiwn / bottom up design.

 

it does raise an interesting question - what is your goal? why multithread?  more fps?   cores are there so use them?    my game is too slow?   that may be the first question to ask.   why?  never start anything without a really good reason why.  that will also tell you the type of approach you ought to take.

Edited by Norman Barrows

Share this post


Link to post
Share on other sites

It's a pretty high-level overview, but I gave a lecture on this recently:

 

Excellent talk, thanks a lot! You mention that there are open source versions or otherwise good information on the net for both complete job systems and lock-free queues. Care to share your favorite ones?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!