IT tutorials
 
Technology
 

Windows Phone 7 : Creating a Game Framework - Benchmarking and Performance (part 2)

10/7/2013 3:12:19 AM
- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019

3. Performance Considerations

Now that we can monitor the performance of our game, let's take a look at some of the things that can cause it to slow down and then determine some approaches to resolving these problems.

3.1. Texture Loading

What happens if we increase the number of planets significantly, perhaps to 1000? This is easily tested by modifying the PlanetCount constant at the top of the BenchmarkGame.cs source file. Give it a try and see what happens.

The result is a dramatic drop in the frames per second, as shown in Figure 2. It now displays a mere 5.9 frames drawn per second.

Figure 2. The benchmark results with 1000 planets

NOTE

This benchmark shows up an important feature of the XNA engine: although the frame rate has dropped all the way down to 5.9 frames per second, the updates per second still stay exactly as they were with just 10 planets. This is because XNA is detecting that the game is running slowly due to the amount of time the sprites are taking to draw, and as a result is calling the game's Draw method less frequently. It prioritizes calls to Update so that the game logic runs at full speed even though the rendering does not. This ensures that the game runs at the same speed across all devices and regardless of processor power being drained by other applications on the phone.

So this large frame rate drop is disappointing, but perhaps that is all the device has the power to draw? There are a large number of sprites after all. In fact, the sprite count is not the actual cause of the frame rate dropping. The causeis the order in which the sprites are being drawn.

Each time XNA draws a sprite, it must pass the texture for the sprite to the graphics hardware ready for it to draw. Most of the information needed to draw a sprite will fit into just a few bytes of data (its position, rotation, scaling, and so on don't need very much memory to describe), but compared with the sprite location, the texture is comparatively huge. It is therefore in our interest to minimize the amount of texture information that is passed to the graphics hardware.

Once a texture has been loaded into the hardware it can be used over and over again without needing to be reloaded, but when another texture is loaded, the original texture is discarded. If you recall, the way we set up the moons and planets in the game was by first adding a planet object and then adding the corresponding moon object. This means that planets and moons are alternating in the GameObjects collection. Every single sprite we draw needs a new texture to be loaded: first the planet texture, then the moon, then the planet again, right through to the end of the sprite batch. In total we end up loading 2000 textures in this configuration. No wonder the game slowed down.

There are various ways to address this problem. The first is to sort the objects in the GameObjects list so that they are ordered by texture. To try out this approach, modify the Benchmark project's LoadContent method so that it calls into AddPlanets_InBlocks instead of AddPlanets_Interleaved. This adds exactly the same number of objects (and the benchmark display will confirm this), but as 1000 planets followed by 1000 moons. If you run this again, you will see that the frame rate has now nearly doubled. In this configuration, XNA has to load only two textures rather than 2000, requiring just one load each of the planet texture and then the moon texture.

If you try this out on both the emulator and on a real device, you will find that the device performance is not nearly as good as that of the emulator. The emulator doesn't cap its frame rate or anything similar, and as a result can display far more updates per second than an actual phone. It is important to performance test your game on real hardware as you are writing it to avoid unpleasant surprises later on.


In a real game, however, it is impractical to expect the objects to always be ordered by their textures. As objects are added and removed through the course of the game, the object collection will naturally become scrambled. There are two additional approaches that we can take to deal with this performance problem: one provided by XNA and one by the game framework.

The XNA approach involves modifying the parameters that we send to the SpriteBatch object when calling its Begin method. Most of our examples have not passed any parameters at all, although we have passed the SpriteSortMode.BackToFront value so that the sprites' LayerDepths are observed.

One of the other sort modes is SpriteSortMode.Texture. In this mode, the LayerDepth is ignored, but instead the sprites are, as you might expect, sorted by their textures. Modify the example project so that it once again adds the sprites interleaved rather than in blocks, and then take a look at its Draw method. You will find three different versions of the sprite batch code: comment out the current version 1 and uncomment version 2.

Despite having added the sprites in alternating order, the frame rate is still high just as it was when we added the sprites in blocks. This has also resulted in just two texture loads for all the sprites.

There are some drawbacks to this approach, however. Most obviously, we have lost control of exactly which sprites are drawn first; as evidence you will see that the moons have disappeared behind the planets and the benchmark text has disappeared behind everything. In addition, using the Texture sort mode means that we cannot use the LayerDepth feature at all.

In many cases, these drawbacks will be of no significance and this approach will work fine. If you need to regain some of the control of the rendering process, use the second approach.

The GameHost.DrawSprites method that we have been calling actually has another overload that allows a texture to be passed in as a parameter. When this version is used, only sprites that use the supplied texture will be drawn; all others will be completely ignored. This allows us to draw the sprites grouped by texture, but to also be in control of which textures are processed first.

If you comment out version 2 of the Draw code and instead uncomment version 3, you will see this approach in action. The moons are now rendered in front of the planets, and the benchmark text is in front of everything.

However, none of these approaches gives the exact same rendering of the planets and the moons that we started with, in which each moon went in front of the planets defined earlier in the GameObjects list and behind any planets defined after. Some effects cannot be achieved when sprite ordering is in place and for which there is no alternative but to repeatedly load the same textures into the graphics hardware. The important thing is to be aware of this performance bottleneck and to reduce or eliminate it wherever possible.

In most cases, the performance degradation will not be as significant as in this example. Use the BenchmarkObject to help you to identify drops in frame rate as soon as they occur so that you can focus your efforts to track them down as quickly as possible.

3.2. Creating and Destroying Objects

You are probably aware of the .NET garbage collection feature. Once in a while, .NET will reach a trigger point that instructs it to search all its memory space, looking for objects that are no longer in use. They are marked as unneeded and then the remaining active objects are reorganized so that they use the system memory efficiently. This process stops memory from becoming fragmented and ensures that the application doesn't run out of space to create new objects.

This has many benefits, primarily by simplifying the creation of objects and removing any need to free up memory once those objects are no longer needed. The disadvantage is that, when .NET does decide to perform a garbage collection operation, it can have a noticeable effect on your game. We therefore need to try to reduce the amount of garbage that we create as far as possible.

The number one rule is to try to avoid creating temporary object instances while the game is running. There will, of course, be instances where it is essential (all our game objects are object instances after all!), but we should keep our eyes open for instances that can be avoided and remove them wherever possible.

NOTE

Due to the way that .NET manages its memory, we need to worry about garbage collection only when using objects. A structure (struct) has its memory allocated in a different way that does not result in garbage being generated. It is therefore perfectly okay to create new Vector2, Rectangle, and Color structures, as well as any other struct-based data structure.

You will see examples of this efficient use of object allocation within the default content created when a new XNA project is created. The SpriteBatch object is declared at class level even though it is only used within the Draw method. Declaring it at class level means that it can be instantiated just once for the entire game run, whereas declaring it in Draw would result in a new object being created every time the sprites were drawn.

3.3. Using for and foreach Loops

The foreach syntax is extremely useful and in many cases faster to operate than a regular for loop when using collections because moving from one item to the next steps just one element forward through a linked list of objects. On the other hand, accessing collection object by index requires the whole of the collection to be traversed up to the point where the requested object is reached.

But in Windows Phone 7 XNA games, there is a potential drawback with foreach loops, which means that they need a little extra consideration. These loops create an iterator object and use it to step through the collection items. For certain types of collection, when the loop finishes, the iterator object is discarded and ends up on the pile of objects ready for garbage collection. As discussed in the previous section, this process will increase the frequency of the garbage collection operation and cause the game performance to suffer.

The collection types that suffer this problem are all nongeneric collections and the generic Collection<T> object. For code inside your game loop (anywhere inside the Update or Draw methods), you should either avoid using these collection types or iterate through them with a for loop instead of a foreach loop. It is fine to use foreach for arrays and all other generic collection types, however.

Also be aware that when you do use for loops, if you include a method or property call for the end condition of the loop, your compiled code will call into it for every iteration of the loop. It is, therefore, a good idea to read the collection size into a local variable prior to entering the loop and use it in your for loop instead.

 
Others
 
- Windows Phone 7 : Creating a Game Framework - Benchmarking and Performance (part 1)
- Operating and Monitoring Exchange Server 2013 : Monitoring Enhancements in Exchange 2013
- Operating and Monitoring Exchange Server 2013 : Reporting
- Operating and Monitoring Exchange Server 2013 : Monitoring,Alerting, Inventory
- Active Directory 2008 : Managing Multiple Domains (part 3) - Managing UPN Suffixes, Managing Global Catalog Servers, Managing Universal Group Membership Caching
- Active Directory 2008 : Managing Multiple Domains (part 2) - Managing Trusts
- Active Directory 2008 : Managing Multiple Domains (part 1) - Assigning Single-Master Roles
- Active Directory 2008 : Installing and Managing Trees and Forests - Demoting a Domain Controller
- Windows 7 : Using a Windows Network - Managing Your Network
- Windows 7 : Using a Windows Network - Sharing Printers
 
 
Top 10
 
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
Technology FAQ
- Is possible to just to use a wireless router to extend wireless access to wireless access points?
- Ruby - Insert Struct to MySql
- how to find my Symantec pcAnywhere serial number
- About direct X / Open GL issue
- How to determine eclipse version?
- What SAN cert Exchange 2010 for UM, OA?
- How do I populate a SQL Express table from Excel file?
- code for express check out with Paypal.
- Problem with Templated User Control
- ShellExecute SW_HIDE
programming4us programming4us