Multi-Thread Fun

Published June 28, 2006
Advertisement
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...

Previous Entry Fallback
Next Entry Heap & Smoke
0 likes 4 comments

Comments

TraderJack
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
June 28, 2006 10:23 PM
jollyjeffers
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
June 29, 2006 10:43 AM
SimmerD
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()...
June 29, 2006 12:49 PM
ApochPiQ
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.
June 29, 2006 03:57 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement

Latest Entries

1.2 Almost ready...

1138 views

Sound Paths

1355 views

Stately Progress

1166 views

State Lines

1310 views

Pulsing

890 views

Return to The Ship!

1029 views

Cameras &amp; Boxes

1147 views
Advertisement