Breaking changes in XNA Game Studio 4.0

Breaking changes in XNA Game Studio 4.0

  • Comments 72

I was relieved when the comments on my earlier post about backward compatibility agreed with the approach we chose for XNA Game Studio 4.0. Banjobeni summed up the general sentiment:

"If you break it, break it good."

The initial motivation for breaking changes in XNA GS 4.0 was the addition of Windows Phone, but this is about more than any one platform. A quick history lesson:

Version 1.0 of the XNA Framework was designed around DirectX 9 on Windows. We had little time to create an enormous API, so had to move fast and decisively. In retrospect I think we did a great job choosing the right places to concentrate our design efforts, and I’m proud of what we built, but there were many areas where we decided “hey, we don’t have time to agonize over this detail, so let’s just copy whatever native DirectX 9 does, and move on”.

When we started work on Xbox 360 in the second half of the 1.0 development schedule, some of these hasty decisions needed to be revised (and some were revised further in our 2.0 release), but many were left alone. Even when things didn’t exactly fit the Xbox, they were similar enough that we could squint and say “yeah, that’s close enough to get the job done”.

When we looked at the new phone platform, we found more things that did not work quite the same as on Windows. Had we tried to squint until they looked the same, we would have ended up with our eyes screwed most of the way shut! I’m a perfectionist, and that just didn’t feel good enough.

Ok, let’s change our API in the places necessary to make the phone consistent with our other platforms.

But breaking changes are expensive. Having gone three years without any major breaks, we felt this was a good time to introduce an inflection point, cleaning up our act and setting ourselves up for the future. But we also felt it was important that this be a one time thing. Breaking changes every three years may be ok, but every year, or every six months, most certainly would not. If we’re going to break it, let’s break it good, taking all the pain in one go so we don’t have to break again for many years to come.

So, we took the opportunity provided by the phone to also reduce those nagging Windows vs. Xbox inconsistencies.

We also used this opportunity to improve usability, applying our three years of experience to look at which things cause the most confusion for our customers, and tweaking these APIs to reduce the chance of error.

Finally, we gazed deep into our crystal ball in an attempt to predict the future. This failed miserably (sadly, it turns out I am not psychic at all :-) so instead I made some guesses. XNA Game Studio 4.0 sits on top of DirectX 9 on both Windows and Xbox 360, and we have no immediate plans to move to DirectX 10 or 11, but looking years into the future, it seems at least possible we might someday want to do that. DirectX 11 adds some things that are not in DirectX 9, but it also changes and in some cases removes features. Adding features is relatively painless from a compatibility perspective (it’s easy to imagine how a third profile could someday sit alongside Reach and HiDef) but taking things away hurts deep (it would suck if any such third profile could not be a strict superset of HiDef, in the same way that HiDef is a superset of Reach). So we looked at what it would take to implement our API using DirectX 11, and made sure we didn’t include anything that would make this excessively difficult. I am not promising we will ever support DirectX 11, just saying we did some thinking about this and laid some groundwork so if we ever do want it, we can go there without having to break backward compatibility.

An overarching goal of these API tweaks was that even though we are breaking things, we still want the new API to feel like the XNA Framework you know and love. Some of the details may be different, but existing developer knowledge and design patterns should be easy to move across.

Another goal was to prefer simplicity over complexity. I am a big believer in minimalist design. It’s easy to add new things each time we encounter a new problem, but I think more valuable to hone them down to their core essence, trying to find the minimum surface area necessary to communicate between developer and runtime. It makes me happy that the XNA Framework 4.0 API surface is significantly smaller than the 3.1 version.

I’ll be writing more about these changes and the reasons behind them over the coming weeks, but here is a quick summary of the more significant breaking changes:

  • Replaced StorageContainer.TitleLocation with a new OpenStream API
  • Replaced individual graphics renderstates with a new state objects API
  • Premultiplied alpha is now enabled by default
  • Made it easier to use SpriteBatch with custom renderstates and custom shaders
  • No more SpriteBatch vertex shader magic, so you can easily position SpriteBatch text in a 3D world using BasicEffect
  • Vertex buffers are now strongly typed, each one having an associated VertexDeclaration
  • You no longer need to specify a VertexDeclaration before drawing, because this is implicit in your choice of vertex buffer
  • Vertex buffer sizes are now specified as number of vertices rather than bytes
  • Replaced GraphicsDevice.Vertices with a new SetVertexBuffer API
  • Each rendertarget now has an associated depth buffer: no more DepthStencilBuffer type
  • RenderTarget2D now inherits Texture2D: no more GetTexture method
  • SetRenderTarget atomically sets all rendertargets, rather than changing just one layer
  • Replaced Effect.Begin and End with a new EffectPass.Apply method
  • Removed the low level shader APIs (VertexShader, PixelShader, Set*ShaderConstant)
  • Removed EffectPool, StateBlock, GammaRamp, ClipPlane
  • Removed triangle fans
  • Removed point sprites
  • Changed the Color type from BGRA to RGBA byte ordering

I suspect some of you will have concerns about some of these removals. Don’t panic! This article is already too long, and I’m running out of time to write more, but I am confident once I explain the why, how, and wheretofore of these changes, you will agree they are good and sensible. If there are specific things you would like me to write about first, please let me know via the comments below.

  • +1 for point sprites.

    I can replace them in my game without too much effort thanks to a pluggable particle renderer, but I would have 4 vertices instead of 1 for each particle (or 3 with some clever billboarding).

  • +1 for more info on:

    1.  Clip Planes

    2.  Sharing a single depth buffer between render targets.  

    I'm guessing if the RenderTarget change is an improvement perhaps the GraphicsDevice will no longer require the DepthStencilBuffer to be set to accommodate rendering algorithms that do not read/write to depth buffer...and perhaps the RenderTarget has a constructor that gives the option to not create a DepthBuffer.  Thus, a savings in memory.  I'm really curious to hear about this.

  • Requiring all render targets to have an individual depth buffer does seem a bit wasteful of memory.

    Eg things like tone mapping, blurring, saved textures for distortion mapping, parts of volumetric fog, SSAO etc etc.

    All the types of things the 360 is good at with its insane fill rate... And the extra cost of the buffers is likely to hurt the 360 more with its limited Expensive Graphics Ram(or whatever its called).

    Looking at the CTP, there does not appear to be any options to disable creation of depth buffers(Unless specifying Unknown for a format disables creation, which would be counter intuitive:-(

    Hopefully this will be improved before release?

    Perhaps there is something I dont know about graphics hardware... (eg they almost always create hidden depth buffers along with render targets) or depth buffers are lazy created when the user tries to render with depth buffering enabled(which would be kinda cool, if a little confusing).

  • I reuse a single depth buffer throughout my deferred renderer.

    +1 for hearing about depth buffer reuse. :)

  • How does the linked render target/depth buffer work with multiple render targets?

    Is there no longer any way of changing render target while preserving the current depth buffer? If not, then I'll have to either manually restore depth when sapping to the lighting buffer or accept that occluded lights can no longer be efficiently culled.

  • Does the emulator use the same garbage collector as the actual phone? How close is the emulators speed to real life?

  • No more SetxxxConstant and CommitChange,so what's the best way to update effect parameter?

    Also curious about the behavior of EffectPass.Apply.

    GraphicsDevice will do redundant check when set state object(good), are there other redundant check beside this one?

  • How close is the emulator to the real phone's also from what I here the cortex-a8 and the scorpion arm cpu's are very differant in speed from each other... which one is the emulator trying to match? and at what clock speed.

    Also what about the emulators garbage collector?

    I don't expect to answer this right now but if you could in the next few weeks (if you are allowed) that would be great.

  • > RGBA is the standard color layout in DirectX 10 and 11, and thus also the native layout of most modern graphics hardware.

    Out of curiosity, why did XNA originally use BGRA as the default?

  • > Out of curiosity, why did XNA originally use BGRA as the default?

    Versions of DirectX prior to 10 used BGRA color layout. This is a quirk of older Microsoft platforms (GDI does the same thing) that we're gradually trying to move away from.

  • This has nothing to do with the topic of this post, but since a couple of people have asked about the emulator, I will answer that anyway.

    The emulator is a full functional emulator of the phone behavior, but it does not attempt to emulate performance characteristics. It runs the full phone OS (including the same CLR runtime as the phone) in a virtual machine, but it does not do hardware level timing emulation.

  • btw. I'm not ignoring all your questions about point sprites, rendertargets, etc, just planning on addressing these in a separate article rather than commenting on each question here.

    Keep the questions coming - this is great feedback to make sure my next few articles cover all the things you want to know!

  • Something that XNA really needs is good floating-point performance on xbox. There's no use of SIMD instructions. Without SIMD, most of the gameplay and physics math runs VERY slow. Have you (plural you) ever thought about that?

    I can't wait for using it.

  • Apparently nothing has been done to improve Matrix operation in the Compact Framework on the XBOX Platform. I still think this is something that should be addressed as Game programming without SSE code is a big limitation.

  • Hmm, from what I remember about native 360 code performance, the big problem is branching on float compares. Otherwise the standard float unit on the 360 is pretty good.

    So I would suggest trying to remove comparisons in your math intensive code. Which would be a lot easier with some VMX extensions to the CLR, so we can use the more sophisticated predication etc. However a single intrinsic style function for fsel(assuming the CLR doesnt generate it) would probably help in this area.

    So do the Math.* operations use branchless versions, eg Min,Max etc? I would guess not.

Page 3 of 5 (72 items) 12345
Leave a Comment
  • Please add 5 and 4 and type the answer here:
  • Post