The Microsoft XNA logo, just the letter xna with the downward slash of the X colored orange

XNA vs Silverlight vs Native Code

If you write a game in Flash, you will have to accept some performance limitations and make some compromises in terms of available technology (eg. no Ageia PhysX or hardware shaders for you). But nearly everybody can play the game right in his browser, dramatically expanding the number of people that see your game.

Now Microsoft is hurling a competitor to Flash at the market: Microsoft Silverlight. It is based on the .NET Compact Framework 3.5 and WPF, which makes it about 1000 times more powerful than Flash. WPF also includes 3D graphics and is way faster than flash, allowing for full-screen animations where flash would slow down to a crawl. It’s being ported to Mono/Linux as well, with the help if none other than Microsoft!

This got me thinking about doing a comparison of the new contenders versus traditional C or C++ development. Here it is:

Size

Indie developers generally consider the size of their games as being important. The assumption is that a greater number of customers will try a game of around 3-5 MB than a game sized hundreds of megabytes.

  Once Per Game
Visual C++ 2005
(statically linked)

with DirectX 9.0c End-User Runtime 4.0 MB1
+ 4.0 MB

+ 1.1 MB
large binaries
Visual C++ 2005
(dynamically linked)

Visual C++ 2005 SP1 Redistributable Package (x86) 2.6 MB
+ 2.6 MB

with DirectX 9.0c End-User Runtime 4.0 MB1
+ 6.6 MB


large binaries
.NET / XNA .NET Framework Version 2.0 Redistributable Package (x86) 22.4 MB
XNA Framework Redistributable 1.0 Refresh 1.9 MB
DirectX 9.0c End-User Runtime 4.0 MB1
+ 24.3 MB

small binaries
.NET / Silverlight Silverlight 1.0 Runtime 1.4 MB2
+ 1.4 MB

small binaries

1 You can add and remove specific versions from the DirectX installer in any way you want. By removing all but the version required for the XNA framework, you can cut down the DirectX End-User Runtime to just 4 MB. Such a cut-down version is actually included in the redist folder of XNA Game Studio
2 Silverlight includes a special version of the .NET Compact Framework 3.5 and does not require the normal framework to be installed. It is the goal of the Silverlight team to keep the whole package below 5 MB.

Update: As the Zman pointed out, if you’re actually making an indie game which uses DirectX (a lot of indies still would go for Win32/GDI), you’ll need to include the DirectX 9.0c Redistributables as well. I’ve added the new size below the original estimate.

From this perspective, XNA doesn’t look very attractive. Users need to install the .NET Framework 2.0, the XNA Framework and a more or less recent DirectX runtime. However, you can subtract 22.4 MB from the installer size once Windows Vista has settled. XNA also is the only platform that can be deployed to the Xbox 360.

Speed

Comparing the speed of .NET versus C++ has always been a matter of debate. One group will insist that you have to implement all optimizations you can think of in each language, another group will insist that the code needs to perform the exact same steps in both languages.

Something you might find interesting then are the are the investigations of Washu. Instead of comparing some benchmarking programs, she has compared the actual machine code generated by the .NET compiler with hand-optimized SSE2 code:

Playing With The .NET JIT
Playing With The .NET JIT Part 2
Playing With The .NET JIT Part 3
Playing With The .NET JIT Part 4

The results are that the native image generator produces code that is nearly on par with hand-optimized assembler code. The native image generator is an offline compiler .NET that produces optimized machine code. It ships with .NET and some installers (for example, the one from Paint.NET use it to precompile applications when they are installed.

2 thoughts to “XNA vs Silverlight vs Native Code”

  1. For a comparable experience you need to include the DX redist with your C++ games too unless you manage to avoid using D3DX, XInput and XACT and you can guarantee XPSP2

    If you target Xbox only then there is none of those requirements – but of course the poor PC needs GSE installed and you can’t sell it.

    I’ve been complaining to MS about this since the MDX days and they are not interested in the incremental installer type scenario so we are stuck including 25Mb of crap with each game ‘just in case’. Thanks for posting this…

  2. While I haven’t posted part 5 (and I really should), I though I would briefly mention it here.

    One of the things I investigated (and will eventually get around to writing up and posting) is whether reordering of code could improve the JIT produced assembly. For instance, as you may note in the assembly dumps, the vector dot product has 6 bounds checks to ensure the integrity of the arrays (i.e. they are at least the proper size). However, one might note that simply testing for the largest size would save 4 checks. But, if one adds the constraint that the exception produced will tell the exact index that failed, then we can’t eliminate the other 4 (this constraint doesn’t exist, and a simple case of static analysis would eliminate the redundant checks…).

    By reordering the vector code such that the largest index of each array is accessed first, one might assume that one could assist ngen or the JIT during its static analysis in removing the redundant checks. For example:

    public static void InnerProduct(float[] x, float[] y, out float result) {
        result = x[3] * y[3] + x[2] * y[2] + x[1] * y[1] + x[0] * y[0];
    }
    

    However this will not generate the expected outcome, and instead all 6 checks will remain, just in reverse order, which is a pitty, but future work (.net 3.5 for instance) may fix these short comings.

    I should note that I specifically wrote my test code to ensure that the JIT could not optimize out the exception checks, as they were important to the overall test framework. Simple tests ,such as calling to that function and passing a properly sized array, will allow for static analysis to eliminate the exception checks entirely. However when one is dealing with a realistically complex code base static analysis cannot make the assumptions, in the time allocated for it, that it can with simplistic examples. Hence the code was designed to explicitly force trivial static analysis to fail while allowing for more complex methods to succeed. One can see the more complex methods in the ways in which it optimized returning a float vs setting an out float parameter.

Leave a Reply

Your email address will not be published. Required fields are marked *

Please copy the string nZ6Rpn to the field below:

This site uses Akismet to reduce spam. Learn how your comment data is processed.