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.
> XNA 3.1 didn't complain when there were missing items.
3.1 just passed this through to the driver, which depending on hardware might return 0s, or NaNs, or might crash, or lockup, etc. This situation resulted in undefined behavior, which happened to work out ok on your particular card+driver, but would have caused compat issues if you tried to ship this code to customers with different hardware.
No, there isn't a way to tell shaders that data is optional. If a shader uses an input, the caller must provide that input. In 4.0 we check that you are doing this right, so you can be sure that your code will work reliably on different machines.
The error message should tell you which specific vertex channel is missing, so you can either add thsi to your model data, or change your shader to not require it.
I was using hashtable in 3.1 but in 4.0 for wp7 its not there ... can u suggest me an alternative ...
> I was using hashtable in 3.1 but in 4.0 for wp7 its not there ... can u suggest me an alternative ...
I'm also getting the InvalidOperationException "The current vertex declaration does not include all the elements".. I'm not sure how to tell which channel its referring to. It doesn't say more than that. I'm getting the exception when I'm binding a VertexBuffer of type VertexPositionColorTexture. TexturesEnabled is true, VertexColorEnabled is true, the Texture is set to a normal Texture2D which is loaded fine. I also ran the EffectsPass (just a count of 1 of them in the list) prior. All 3 matrices set.
Kyle: this is on Windows Phone, right? Try running your game on Windows, that'll give a more detailed error message.
for some questions you couldnt see answers on xna 4.0 try davidtblogs.wordpress.com
uhm one thing i noticed is Compiled effect class is missing but its not all in any place telling its missing
hmm i had a couple of shaders in strings and prebuilt it in engine that way i dont have to keep adding the effects in every project i make
soo question is without the compiled effect class how can i compile strings and put them in effects?
Opelion: Game Studio 4.0 effect compilation is handled by the Content Pipeline. You can do that in Visual Studio, or automate it using MSBuild, or call into the EffectProcessor directly from your own code, but this functionality requires the Content Pipeline so is not available on computers that do not have Game Studio installed.
hmm so not even the run time of XNA 4.0?
1. Keep up the good work and the good community support
2. Did you post the article/blog which should give detailed answers to the questions above yet? If so, can you post a link to it here?
"No, there isn't a way to tell shaders that data is optional. If a shader uses an input, the caller must provide that input. In 4.0 we check that you are doing this right, so you can be sure that your code will work reliably on different machines."
According to this MSDN article, the shader will simply init values that are not within the stream to 0's.
From Writing HLSL Shaders in Direct3D 9 (msdn.microsoft.com/.../bb944006(v=VS.85).aspx):
"The input structure identifies the data from the vertex buffer that will provide the shader inputs. This shader maps the data from the position, normal, and blendweight elements of the vertex buffer into vertex shader registers. The input data type does not have to exactly match the vertex declaration data type. If it doesn't exactly match, the vertex data will automatically be converted into the HLSL's data type when it is written into the shader registers. For instance, if the normal data were defined to be of type UINT by the application, it would be converted into a float3 when read by the shader.
If the data in the vertex stream contains fewer components than the corresponding shader data type, the missing components will be initialized to 0 (except for w, which is initialized to 1)."
LotusXP: that article is talking about missing components /within/ a data channel, for instance if you provide a float3 position but the shader asks for float4 data. That behavior is well defined as described in the MSDN article.
But this is not the same thing as the shader asking for a data channel that is not present in the vertex data at all, for instance trying to use a texture coordinate when no such value is available. This latter situation is undefined behavior. On some systems you will get zeros, on others random values, and some machines will crash or hang. Really not something you ever want to be doing!