Content Pipeline optional

Popular XNA myth #623: "XNA forces me to use the Content Pipeline any time I want to load data into my game".


Short Answer

Not true! The Content Pipeline is (almost) entirely optional. If you prefer to do things some other way, you are most welcome to use any of the varied .NET I/O technologies:

  • Add data files (binary, XML, text, or whatever else you prefer) directly to your main game project
  • Don't add them to your content project (that is specifically for building data with the Content Pipeline)
  • Set their Build Action property to Content, and Copy to Output Directory to Copy if newer
  • In your game code, call TitleContainer.OpenStream, and pass the resulting stream to whatever I/O API you prefer to use

But of course, 'possible' and 'easy' are not the same thing. If you choose not to use our built-in Content Pipeline, you should expect to have to do some work to replace it. Depending on the format of the data you are trying to read, this could range anywhere from trivial to very hard indeed.


Longer Answer

It is important to understand that the Content Pipeline has several layers. At the core is an infrastructure which provides generic services for building and loading any type of content:

All that stuff is just regular C# code. If you wanted, you could write your own version from scratch that would do all the same things in the same way. It'd take you a while, but it would be possible.

Layered on top of the generic infrastructure, we provide built-in support for the most important types of content:

  • Importers for common graphics and audio file formats
  • A build time .NET object model for representing the data returned by these importers
  • Processors for turning this object model into whatever format the runtime XNA Framework wants the data to be
  • Assorted helpers for common data manipulation operations, which make it easier to write your own processors

Again there is no magic here. You could reimplement all this yourself, given sufficient time, skill, and determination.

So what CAN'T you do yourself?

It all boils down to what runtime type you want to load into. It's no use being able to read whatever you like from whatever files you like, if you then have no way to set the data into its final resting place:

  • If you are loading into a type that you created yourself, there is obviously no problem
  • If you are loading into one of the XNA Framework types that have byte[] constructor parameters or SetData methods (eg. Texture2D, VertexBuffer, SoundEffect), again there is no problem: just create the object and set your data into it
  • Some XNA Framework types (Texture2D, SoundEffect) provide a FromStream method that can make this easier (but be warned: FromStream is usually slower than loading via the Content Pipeline)
  • There are four XNA Framework types that have no public constructors or SetData methods, and thus no way to get data into them other than through the Content Pipeline. For these types, you must either use the Content Pipeline, or not use the type at all:
    • Model
    • SpriteFont
    • Song
    • Video

Replacing the built-in Model class is actually a common, sensible, and easy thing to do. Replacing SpriteFont is more work, but still possible. Replacing Song and Video is not really feasible, so you do indeed have to use the Content Pipeline to build music and video data.


Note: this article refers to XNA Game Studio 4.0. Some details varied in previous versions, but the principle remains the same.

Comments (9)

  1. SC says:

    I'd really love to see a public constructor for SpriteFont one of these days… 🙂 It's particularly irksome since it's tightly coupled with SpriteBatch.

    Also curious about why Texture2D.FromStream might be slower than the Content Pipeline.

    I really wish the content pipeline was *truly* optional in the sense it was a layer over top of the public utility classes – internal constructors just make things a nightmare for games that want to support user created content or custom serialization formats. I realize that the internal constructors are there to avoid exposing half-baked public APIs, but we've been waiting years and years for these now.

  2. ShawnHargreaves says:

    > curious about why Texture2D.FromStream might be slower than the Content Pipeline

    The Content Pipeline has already decoded PNG or JPEG data, converted to DXT format, generated mipmaps, etc, so loading is just a block read into a byte array that can be copied directly into a GPU texture.

    FromStream reads from PNG or JPEG, which are nothing like GPU formats, so much more conversion work is required.

    > I really wish the content pipeline was *truly* optional in the sense it was a layer over top of the public utility classes

    It truly is an optional layer over public APIs, except for the four classes I listed at the end of this article.

    In the case of Model, we view that as more of a quick+dirty example to help get beginners started, not the be-all and end-all for more advanced users. It's designed to be easily replaced, and we expect pretty much every expert game dev or engine author to replace it, so we see little value in making it more extensible.

    In the case of SpriteFont, we chose not to expose the internal structure because that is somewhat complex and subject to change. We wanted to reserve the right to change implementation details without breaking customer code, which requires a level of encapsulation.

    In the case of Song and Video, there's no deep reason for them not to be user constructable. They just aren't 🙂

  3. XZodia says:


    Texture2D.FromStream can be slower because it creates a temporary file to store the stream and then loads the file…

    Seems rather stupid, I know…

  4. ShawnHargreaves says:

    > Texture2D.FromStream can be slower because it creates a temporary file to store the stream and then loads the file…

    Not so.  You must be thinking of Texture2D.FromFile in Game Studio <= 3.1.

  5. FieldsOfCarp says:

    I thought the content pipeline was one of the best things in XNA (of course after the graphics API that is ;). There is a certain pleasure in writing custom content pipeline extentions and it all fits in together pertty nicely.

  6. Ultrahead says:

    > " if you then have no way to set the data into its final resting place:"

    You mean, other than by using Reflection, right?

  7. bSinc says:

    What i don't understand is why you guys don't include the Content Pipeline Assembly within the XNA Redist so that Artist don't have to install GSE and VS just for testing content in a game. I know in windows we just can load textures "FromFile" but i really want to use the content pipeline within my Scene Editor for example. Will we see a change in XNA 4?

    Sorry for my English it's not my native language.

    PS: Where can i send requests to the XBOX Live Team so we finally can have Avatars on the PC. I Don't understand why i can only create Avatars on XBOX and Phone. Don't forget the PC Guys! It's still a very very important Gaming Platform!

  8. RRivero says:

    What if I want to create an XNA library, but I want the shaders to be embedded with it? What's the best way to tackle it?

  9. David Davidson says:

    Hey Shawn, not sure if you'll ever read this, but whatever.

    Could you shed some light on Mipmap generation with Texture2D.FromStream? I tried it out today and I'm quite happy with the results, but I can't figure out how to get mipmapping working. I'd quite like to precompute it, but I can't figure out how I would embed mipmap data in any of the formats that FromStream can use (it's probably impossible). I suppose I could do it on the fly with a wrapper of FromStream that would automatically generate mipmaps, but they would probably be lower quality so I'd like to hear from you first if I can.

Skip to main content