Shawn Hargreaves Blog
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."
"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:
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.
While I like the simpler API, I have some *serious* concerns about the features you're removing and how it will impact XNA performance, usability, and flexibility for serious developers.
"Removed the low level shader APIs (… Set*ShaderConstant)"
The xna 3.x SetConstant methods are considerably faster than CommitChanges.
With CommitChanges now missing how are effect parameters set while an effect pass is active? And how does this perform compared to CommitChanges / SetConstant?
If the new method is slower than SetConstant, then SetConstant should not be going away - it is a critical part of making xna Effects efficient.
"Removed ... ClipPlane"
Regardless of how this is implemented in the driver it's handled *automatically* for the user and for *all* rendered objects. Telling users they need to code clipping plane calculations into the custom shaders of all their objects, just to support simple reflections (which should be object independent) is ridiculous.
Is this code included in BasicEffect, DualEffect, and SkinnedEffect? How will the core effects work with reflections?
Clipping planes are also an important tool used to optimize complex rendering, especially in forward rendered situations.
CompiledEffect and the ability to load effects dynamically is also missing. At the very least loading game resources dynamically should be supported on Windows. For developers with editors this functionality is critical, and unfortunately MSBuild and the content pipeline is far too slow for real-time use.
I haven’t had the time to dive into XNA 4.0 further, so I’m sure there are more missing features I’m not aware of yet. But I’m concerned that serious developers and their needs are not being considered at all here.
Shawn, thanks for answers - I feel much more secure now ;)
"Removed point sprites"
Id like to hear about why are we losing point sprites.
Removal of point sprites looks like a big problem. The reason being that you can do an expensive VS calculation for a point sprite and it only happens once, wheras for a quad it is repeated four times. Not a big issue on Windows with modern GPUs, but I'm pretty sure that would be a serious performance hit on the X360.
Something I've been meaning to ask, did you add pass-by-reference versions of Effect.SetParameter? It's a very heavily used method in most 3D/non-SpriteBatch games, but as of XNA3.1 it only accepts pass by value, which struck me as odd when all the vector maths functions have pass-by-reference versions. Is there some kind of hidden parameter validation going on that wouldn't work without immutable arguments?
Ok apparently there are more problems:
"Each rendertarget now has an associated depth buffer: no more DepthStencilBuffer type"
How do you share depth buffers between render target?
When shadow mapping, several shadow maps or pages will share a single depth buffer to reduce memory usage - how is this accomplished in XNA 4.0?
(and what happened to my last comment? :)
Thanks for so quickly answering my previous question. Now I have some questions on how to get the DynamicSoundEffectInstance stuff working. I tried to get a 440hz A sinusoid playing. It has the right pitch, but I can't seem to get that pure sound that it's supposed to be, it either sounds like a sawtooth or some other strange waveform. Here's what code I'm using:
for (int i = 0; i < 480000; i++)
wave[i] = (byte)(Math.Abs(Math.Sin(441.0*i/96000*Math.PI))*256);
I'm not sure how to handle negatives and where to zero it.
Being a completely blind developer, I’m interested in the audio API. Can you please talk about some of the changes in 4.0? More specifically, are there any changes in 3D audio? I thought I heard something about being able to stream sounds without using the XACT tool, which is not accessible with screen reader software.
All of that sounds great to me! Except for the point sprites which you seem to have saw coming. : j
But not worried, all the work arounds seem justifiable. Excellent work!
Ok guys, here's the deal: I'm not going to respond to individual followup questions in this thread, but don't worry, I'm not ignoring you: it's just that there are many different topics coming up here, all of which deserve to be addressed in far more detail than will fit in this comment box! As soon as I have time (ie. when I get back home after MIX) I will be making a separate post on all the questions raised here, so I can make sure I properly explain everything in the proper amount of detail. I'll start with the things that the most people asked about here. Please be patient while I work through these many topics!
I also just want to reiterate that these changed were absolutely designed to benefit skilled developers who are making high end games, and not just beginners!
Hey Shawn, since you mentioned the topic of Breaking changes in XNA 4.0, I thought I'd share an issue I ran into last night while upgrading my XNA 3.1 project to XNA 4.0.
It seems you guys have changed the signature to SpriteBatch.Begin. Before, I was calling
Color modColor = Color.White;
_spriteBatch.Draw( _circle, _position, null, modColor, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 0 );
modColor.A = 100;
_spriteBatch.Draw( _circle, _position2, null, modColor, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 0.5f );
but this didn't compile, so I switched it to the most seemingly logical equivalent in XNA 4.0:
_spriteBatch.Draw( _circle, _position, null, modColor, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 0);
_spriteBatch.Draw( _circle, _position2, null, modColor, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 0.5f);
When rendering, these two calls do not do the same thing as I would have expected. Here is the side by side comparisons of XNA 3.1 vs. 4.0
> I tried to get a 440hz A sinusoid playing. It has the right pitch, but I can't seem to get that pure sound that it's supposed to be
Dynamic audio uses 16 bit PCM format.
If you need more help with this, I would recommend asking on the creators.xna.com forums, where our audio dev can help you out (I only know about the new audio stuff from a high level, not all the gory details of how to use it)
>Changed the Color type from BGRA to RGBA byte ordering
Shouldn't it have been ARGB? /wonders
> Shouldn't it have been ARGB? /wonders
RGBA is the standard color layout in DirectX 10 and 11, and thus also the native layout of most modern graphics hardware.
Eek! No more point sprites or clip planes? Say it ain't so :(
+1 for reconsidering this...
I would like to know about the DrawInstancedPrimitives method and how that works and what platforms it's available on.