Sign in to follow this  
  • entries
    235
  • comments
    509
  • views
    172053

Multi-Thread Fun

Sign in to follow this  

73 views

As we're finishing up the mountain temple level, I am needing to build the lightmaps and navgrid more often. Normally I run with the lightmaps set to 1% resolution to speed things up, and turn off the navgrid generation ( so the enemies just sit there ).

So, I thought I'd take advantage of the dual core workstations I have and make the lightmap code multi-threaded.

My first step was to read up on win32 threading - it had been a long time since I looked at it, and determined what sort of sync primitives I would need.

The lightmap routine goes through each light in the level, finds world tiles ( chunks of the world geometry ) that might be lit by the light, then proceeds to cast the shadow rays, putting the results into PixelBuffer objects, and later gives them to the TextureMgr as textures.

My first attempt simply created a thread for each tile lit by a light. I knew this would be overkill, and possibly be a really bad idea for outdoor levels, but it was an easy start. On a small level, I got a 50% speed up for a small indoor level.

I made a few small fixes, like not spawning threads when I only had 1 tile in a light range, which was a 2% speedup from that.

Next, I decided to be a bit smarter, and created threads in packs of 8, and wait for all 8 to finish before spawning the next 8. Yes, I know it would be more efficient to keep spawning threads as each one finishes, but I was going for the low hanging fruit.

With this change, and the existing 1-thread optimization, I was able to get a ~55% speedup on the temple level lightmap generation time.

Tomorrow I may thread-ify the navigation map generation code. It will have more critical sections than the two used in the lightmap code, so it may not be as good of a speedup. We'll see.

I spend today tracking down a memory heap problem. Now, I pretty much never get pointer or heap problems, so it was fairly baffling. I was able to track it down to some code in the mesh attachment system ( which I did not write, and which does use pointers ). It seems that in one of my saved games, I picked up the weapon of a dead enemy, but the weapon's attachment pointer wasn't cleared out properly, which caused the gun's attachemnt pointer to be spuriously deleted, while still being referenced by the original holder.

This is why I use IDs. You get a nice level of indirection to check the validity of things. It's undoubtedly a speed hit to dereference ids, but they save to disk nicely, translate across networks well, and don't crash on ya...

Sorry, folks, no pix today...

Sign in to follow this  


4 Comments


Recommended Comments

You're very impressive. Where do I find out more about your project? See, I was around when you first made this journal (check your first ever post for my comment), but I faded into nothingness. Now I'm making my super-awesome comeback, and I'm very interested with what you've done.

-IV

Share this comment


Link to comment
So it wasn't too painful to drop in some MT action then... I'm gonna have to look into that in the future, but figured I'd wait till I had a project that I could design MT'ing in from the start.

Also - you get the speed boost on the dual-core machine, but do you get any change (up or down) for a traditional single-core machine?

Keep up the good work!
Jack

Share this comment


Link to comment
I found the most painful part of the MT thing the inability to find good resources on the net.

Maybe it's one of those things that you get working and then don't really think about anymore once you figure it out...

I ended up using a single criticalsection object in two sections of code - one that updated the material records for the world tiles with bounding boxes, etc. and the other than added things to the texture mgr ( and thus to d3d ).

I didn't create d3d in multi-threaded, so I had to ensure that only one thread at a time made any d3d calls.

To really do the MT thing right, I think you would want a task system that could spawn off multiple threads, and have tasks queued to release when new threads opened up using WaitForMultipleObjects()...

Share this comment


Link to comment
I hear you on the ID thing. I've come to enjoy using a std::map<ID, pointer*> type idiom so that the overhead of the lookup is trivial, pointers can still be used directly when needed by the "internals" of some module or subsystem, and I have an incredibly convenient way to find leakages and referencing problems.

Share this comment


Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now