|
|
Useful XNA Framework tips
Last post 11-20-2007, 6:26 AM by TeaBean. 26 replies.
-
03-29-2007, 10:53 AM |
-
Bill Reiss - MVP
-
-
-
Joined on 03-05-2007
-
Tampa, FL
-
Posts 369
-
-
|
Useful XNA Framework tips
Not sure if this is what you're looking for, but here's a quick tip: In the SpriteBatch.Draw calls that take an origin vector, the origin is specified in source resolution, so no matter how the sprite is scaled, the origin will remain the same. This caused me all sorts of trouble but once I got used to it, it actually makes the code much simpler when scaling to multiple resolutions.
Bill Reiss - XNA Tutorials for Beginners at bluerosegames.com
|
|
-
-
03-31-2007, 4:08 AM |
-
Debesciak
-
-
-
Joined on 03-27-2007
-
-
Posts 143
-
-
|
float aspectRatio = (float)1024 / 768; or 1024.0f / 768.0f otherwise it will cast to int and return 0.
|
|
-
04-02-2007, 12:11 AM |
-
EyeCrust
-
-
-
Joined on 03-05-2007
-
USA
-
Posts 6
-
-
|
Check out the different overloaded version of the SpriteBatch Begin() function and you'll different useful versions of it. One of them allows you to save the state of the graphics device which gets reset again when you call the End() function.
Currently working on TerraSuite, a world-building tool built using XNA!
|
|
-
04-02-2007, 12:11 AM |
-
EyeCrust
-
-
-
Joined on 03-05-2007
-
USA
-
Posts 6
-
-
|
This isn't necessarily related to XNA but more towards game programming. If you're creating a ton of objects that are updated and drawn the system can slow down to a crawl within minutes and you'll find yourself getting less than 1 frames per second. A good strategy is to develop an object manager that recycles the objects that you're using when they die or are removed from the game world. This way when you need to get a new object, instead of calling new and use memory allocation all over again you can just get the references from the manager, reset a few properties, and get a "new" object without the cost of allocating new memory on the heap.
Currently working on TerraSuite, a world-building tool built using XNA!
|
|
-
04-02-2007, 1:49 AM |
-
Bapa
-
-
-
Joined on 03-06-2007
-
Calgary, Alberta - Canada
-
Posts 197
-
-
|
EyeCrust... I love you :) That's a great idea. As for me... Uhm... When you're creating a 3D game, and such have lots of level-geometry and models running around, using "foreach" to render all of the meshes is a bad idea. This is because whenever you hit a foreach, it actually creates allocates a new object, which results in many, many unnecessary object allocations per second.
If efficiency is a must, don't use foreach. Make your own way of looping through all the meshes.
|
|
-
04-02-2007, 10:12 PM |
-
Joel Martinez
-
-
-
Joined on 03-05-2007
-
Orlando, fl
-
Posts 705
-
-
|
EyeCrust:... without the cost of allocating new memory on the heap ...
Just for the record, the cost of allocating things in .NET is near nothing ... almost literally just incrementing a pointer. The real cost of "new" objects comes when the garbage collector runs and tries to reclaimed unused objects. This is particularly true on the xbox360.
Joel Martinez Blog: http://codecube.netPlay Videos on an XNA Texture: Scurvy Media
|
|
-
04-03-2007, 10:29 AM |
-
Jamezila
-
-
-
Joined on 03-05-2007
-
Central NY
-
Posts 118
-
-
|
I've gotten killed by GC before. My main conclusions were: - don't use String.toLower() and - don't use collections. Based on the profiler and performance monitor, using 4 technique collections per render was giving me 4000ms of GC per collection.
skasoftware.com
|
|
-
04-03-2007, 11:31 AM |
-
04-03-2007, 12:32 PM |
|
|
Jamezila:
That seems a little over the top to me - collections are useful! If you're going that far, why not just say "don't write any code at all", which would run incredibly fast, but not be very interesting :-) Certainly there are some things you can do with collections (as with any complicated code) that will cause lots of garbage. The tricks is to understand how to use them well. This is a good place to start: http://blogs.msdn.com/etayrien/archive/2007/03/17/foreach-garbage-and-the-clr-profiler.aspx
-- XNA Framework Developer blog - homepage
|
|
-
04-03-2007, 1:44 PM |
-
Jamezila
-
-
-
Joined on 03-05-2007
-
Central NY
-
Posts 118
-
-
|
I'll change to: - don't use collections for reference values where said collections are instantiated several times per frame And fyi, I think I've managed pretty well in spite of being deathly scared of foreach. A long time ago, in a land far far away, people got along just fine with arrays :) Shawn, I read your blog all the time; I read your post on optimizing for readability, performance, etc. I believe readability is important, and think a for(i = 0; i < array.length; i++) loop is just as readable as a foreach loop. However, when doing a bit of snippet pasting, I (irresponsible young C# developer) accidentally introduced about 4000ms of GC at least once a minute which had a substantial effect on gameplay--I had to run the Performance Monitor and CLR Profiler to find the culprit foreach calls.
I just think it bears mentioning that [irresponsibly] using foreach, unlike using straight up arrays, can lead to a few days of lost productivity and hair-pulling.
skasoftware.com
|
|
-
04-03-2007, 2:06 PM |
-
leclerc9
-
-
-
Joined on 03-26-2007
-
-
Posts 15
-
-
|
Well, instantiating collections several times per frame is far different than enumerating them! You wont get anywhere near 4 seconds of garbage collection time per minute by enumerating collections, but you will get 4 seconds per minute if you are allocating several megabytes of memory per frame. The belief that "foreach" is slow is misguided in the majority of cases: http://blogs.msdn.com/brada/archive/2004/04/29/123105.aspxI also suggest reading the msdn patterns and practices guidelines on collections that are referenced from that page.
|
|
-
04-03-2007, 2:50 PM |
-
-
04-03-2007, 11:10 PM |
-
Jamezila
-
-
-
Joined on 03-05-2007
-
Central NY
-
Posts 118
-
-
|
Well, like they keep saying, they're not evil; you just have to know how to use them, etc. I'm just in the habit of using arrays and then for loops to iterate through them, and it just so happens that the one time I use foreach (from an official msdn snippet, mind you) I end up in a heap of trouble. But I believe that what they're trying to tell me is that if I have BloodyHead [] bloodyhead = new BloodyHead[64]; ... for (int i = 0; i < bloodyhead.length; i++) is exactly the same as foreach(BloodyHead bh in bloodyhead) in the final build. Which is well and good, and I guess it can be better for readability, but I suppose for someone who grew up on for loops and fears change, does it really make that much of a difference?
skasoftware.com
|
|
-
04-04-2007, 12:35 AM |
-
SwampThingTom
-
-
-
Joined on 03-05-2007
-
Fairfax, VA
-
Posts 342
-
-
|
Jamezila:Which is well and good, and I guess it can be better for readability, but I suppose for someone who grew up on for loops and fears change, does it really make that much of a difference?
Nope, you should use whichever you find most readable and easy to program. I think what Shawn and others (including me) have been trying to negate is the idea that foreach, or collections, or passing large structures by value are always bad and need to be avoided at all costs for performance reasons. The idea that foreach is bad is just not true. Which I know you know, but apparently some others here are slower at picking up on the message! ;-) Tom
Advice from the Swamp
|
|
-
10-25-2007, 2:06 PM |
-
Swordshock
-
-
-
Joined on 07-30-2007
-
-
Posts 277
-
-
|
Bapabooiee:
As for me... Uhm... When you're creating a 3D game, and such have lots of level-geometry and models running around, using "foreach" to render all of the meshes is a bad idea. This is because whenever you hit a foreach, it actually creates allocates a new object, which results in many, many unnecessary object allocations per second.
If efficiency is a must, don't use foreach. Make your own way of looping through all the meshes.
Lies, all lies. =P The amount of time used in allocating an enumerator is extremely short in comparison to the amount of time spent drawing all the meshes. Here it is in math terms:
Let us say that drawing one mesh takes 0.1 ms. We have 1000 meshes we want to draw, so they will take 100 ms. Now we have the option of a for loop or a foreach loop. Let us say that the for loop takes 0.001 ms, one hundreth of the time to draw one mesh, to initialize and that the foreach loop takes 0.01 ms, ten times as long as the for loop and one tenth as long as drawing an entire mesh, to initialize. Then the total times for the for loop and foreach loop methods are 100.001 ms and 100.01 ms respectively. Going from the foreach lopp method to the for loop method is a percent change of [(100.001 - 100.01) / 100.01] * 100% = -0.009% change. That's practically nothing!
The values I used in my example were probably not accurate at all, but I think we can agree that they were accurately proportioned. The foreach loop is clearer and more "to-the point" than the for loop. The extra time spent initializing it is negligible.
|
|
-
10-25-2007, 2:49 PM |
-
Nick Gravelyn
-
-
-
Joined on 03-05-2007
-
Seattle, WA, USA
-
Posts 2,970
-
-
|
Swordshock: Bapabooiee:
As for me... Uhm... When you're creating a 3D game, and such have lots of level-geometry and models running around, using "foreach" to render all of the meshes is a bad idea. This is because whenever you hit a foreach, it actually creates allocates a new object, which results in many, many unnecessary object allocations per second.
If efficiency is a must, don't use foreach. Make your own way of looping through all the meshes.
Lies, all lies. =P The amount of time used in allocating an enumerator is extremely short in comparison to the amount of time spent drawing all the meshes.
To put Baabooiee's idea into a better stated way. Each time you hit a foreach loop you generate a new object on the heap. After that loop ends the GC has to take care of it. If you do a lot of foreach's each frame, you will get lots of unnecessary garbage. We should try and emphasize to everyone that allocations aren't the problem, it's the resulting object being sent to the GC that will potentially cause you problems. Of course do read Shawn's post. For beginners with not a lot going on in their game, you can probably get away with using the foreach loop. If you are rendering lots of models and doing lots of computations, you may want to avoid the foreach so that you don't generate the unnecessary garbage.
Nick Gravelyn -- Microsoft XNA MVP XNA Wiki | Zune Games
|
|
-
10-25-2007, 3:09 PM |
-
10-25-2007, 3:21 PM |
|
|
Also, in the 2.0 framework we have improved several collection types that used to create enumerator garbage so they no longer do so. The theory that foreach is slower than for is simply not true. For some types of collection, a foreach loop will create garbage. Depending on your game, collecting that garbage may take time, but it may also be very quick. It depends. For other types of collection, foreach will not create garbage. For some types of collection, using a for loop and indexing into the collection may cause slow index validation tests, which could be avoided if you used foreach. For other types of collection, for and foreach will both require the same amount of validation work. It depends. But it is just flat out wrong to say that one is always going to be faster than the other.
-- XNA Framework Developer blog - homepage
|
|
-
10-25-2007, 3:35 PM |
-
Nick Gravelyn
-
-
-
Joined on 03-05-2007
-
Seattle, WA, USA
-
Posts 2,970
-
-
|
Shawn Hargreaves:The theory that foreach is slower than for is simply not true.
I definitely didn't try to say either was faster than the other. I actually always did assume the foreach would be faster by using an enumerator instead of indexing. I was speaking more in terms of garbage creation. For some types of collection, a foreach loop will create garbage. Depending on your game, collecting that garbage may take time, but it may also be very quick. It depends.
For other types of collection, foreach will not create garbage.
I didn't know there were types that didn't generate garbage. That's one thing I didn't actually know. I figured all uses of foreach created an enumerator which later got fed to the GC. Learning something new each day I suppose.
Nick Gravelyn -- Microsoft XNA MVP XNA Wiki | Zune Games
|
|
-
10-26-2007, 2:20 AM |
-
Michael Duncan
-
-
-
Joined on 10-16-2007
-
Perth, Australia
-
Posts 33
-
-
|
Bapabooiee:using "foreach" to render all of the meshes is a bad idea. This is because whenever you hit a foreach, it actually creates allocates a new object, which results in many, many unnecessary object allocations per second.
The overhead in startup for a foreach is typically insignificant compared to what is being performed inside the loop.
Cheers, Michael  Member
|
|
-
10-26-2007, 2:45 AM |
-
Michael Duncan
-
-
-
Joined on 10-16-2007
-
Perth, Australia
-
Posts 33
-
-
|
Nick Gravelyn: Swordshock: Bapabooiee:
As for me... Uhm... When you're creating a 3D game, and such have lots of level-geometry and models running around, using "foreach" to render all of the meshes is a bad idea. This is because whenever you hit a foreach, it actually creates allocates a new object, which results in many, many unnecessary object allocations per second.
If efficiency is a must, don't use foreach. Make your own way of looping through all the meshes.
Lies, all lies. =P The amount of time used in allocating an enumerator is extremely short in comparison to the amount of time spent drawing all the meshes.
To put Baabooiee's idea into a better stated way. Each time you hit a foreach loop you generate a new object on the heap. After that loop ends the GC has to take care of it. If you do a lot of foreach's each frame, you will get lots of unnecessary garbage. We should try and emphasize to everyone that allocations aren't the problem, it's the resulting object being sent to the GC that will potentially cause you problems. Of course do read Shawn's post. For beginners with not a lot going on in their game, you can probably get away with using the foreach loop. If you are rendering lots of models and doing lots of computations, you may want to avoid the foreach so that you don't generate the unnecessary garbage.
Hmmm...perhaps but where do you want to stop? I can call any method in any API and I'm pretty sure that somewhere within the confines of the code an object will be created for one reason or another. Whether I made a call to read from a file; play a sound; or read from the keyboard. It all depends on HOW many objects in question. Allocating < 100 per second is insignificant. Objects are inevitable. I really doubt that a few enumerator objects being created per frame are going to significantly impact performance. The MSDN and Creators Club samples run quite well with enumerators. This issue is not specific to XNA but .NET as a whole. .NET has been around for some time now and much performance testing has been done. My c# raytracer just loves enumerators. It's only 10% slower than the original c++ which is the approximate performance hit of moving away from c++ anyway. :)
Cheers, Michael  Member
|
|
-
10-31-2007, 7:57 PM |
-
Mishima Reika
-
-
-
Joined on 03-27-2007
-
-
Posts 6
-
-
|
Michael Duncan:The overhead in startup for a foreach is typically insignificant compared to what is being performed inside the loop.
In fact, sometimes it's free. The JITter is smart enough to convert a 'foreach' to a 'for' when used on Arrays, for instance (disclaimer: I know this is true on the desktop CLR).
The bigger issue with foreach over meshes to draw stuff (as the OP was talking about) is that if you are really worried about performance, chances are you are sorting things by material anyway and you have a custom system for that. Making that adjustment will save you dozens of GC's worth of time per frame.
|
|
-
11-05-2007, 10:42 AM |
|
|