I'm rendering textured quads to an orthographic view in XNA through hardware instancing. On Nvidia graphics cards, this all works, tested on 3 machines. On ATI cards, it doesn't work at all, tested on 2 machines.

How come? Culling perhaps?

My orthographic view is set up like this:

Matrix projection = Matrix.CreateOrthographicOffCenter(0, graphicsDevice.Viewport.Width, -graphicsDevice.Viewport.Height, 0, 0, 1);

And my elements are rendered with the Z-coordinate 0.


I just figured out something weird.

If I do not call this spritebatch code above doing my textured quad rendering code, then it won't work on Nvidia cards either. Could that be due to culling information or something like that?

        Batch.Instance.SpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone);

Edit 2:

Here's the full code for my instancing call.

    public void DrawTextures()

        Batch.Instance.SpriteBatch.Begin(SpriteSortMode.Texture, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone, textureEffect);
        while (texturesToDraw.Count > 0)
            TextureJob texture = texturesToDraw.Dequeue();
            spriteBatch.Draw(texture.Texture, texture.DestinationRectangle, texture.TintingColor);

        // no work to do
        if (positionInBufferTextured > 0)

            device.BlendState = BlendState.Opaque;

            textureEffect.CurrentTechnique = textureEffect.Techniques["Technique1"];

            if ((textureInstanceBuffer == null) ||
                (positionInBufferTextured > textureInstanceBuffer.VertexCount))
                if (textureInstanceBuffer != null)

                textureInstanceBuffer = new DynamicVertexBuffer(device, texturedInstanceVertexDeclaration, positionInBufferTextured, BufferUsage.WriteOnly);

            if (positionInBufferTextured > 0)
                textureInstanceBuffer.SetData(texturedInstances, 0, positionInBufferTextured, SetDataOptions.Discard);

            device.Indices = textureIndexBuffer;
            device.SetVertexBuffers(textureGeometryBuffer, new VertexBufferBinding(textureInstanceBuffer, 0, 1));

            device.DrawInstancedPrimitives(PrimitiveType.TriangleStrip, 0, 0, textureGeometryBuffer.VertexCount, 0, 2, positionInBufferTextured);

            // now that we've drawn, it's ok to reset positionInBuffer back to zero,
            // and write over any vertices that may have been set previously.
            positionInBufferTextured = 0;

  • 2
    \$\begingroup\$ Are your textures powers of 2? \$\endgroup\$
    – Tetrad
    Jun 24, 2011 at 4:29
  • 1
    \$\begingroup\$ Don't use singletons in XNA \$\endgroup\$ Jun 24, 2011 at 5:02
  • \$\begingroup\$ Also, if you simply want to use the default values, pass null for that parameter to SpriteBatch.Begin() (works for everything but SpriteSortMode) \$\endgroup\$ Jun 24, 2011 at 5:04
  • \$\begingroup\$ "I'm rendering textured quads to an orthographic view in XNA through hardware instancing." <- Why not just use SpriteBatch? \$\endgroup\$ Jun 24, 2011 at 5:13
  • 1
    \$\begingroup\$ Andrew - because some of these quads must have the shader applied to it. Some of them doesn't. And I want to draw them in a single call. \$\endgroup\$ Jun 24, 2011 at 6:52

2 Answers 2


SpriteSortMode.Immediate is setting the device state "immediately" you call Begin. You shouldn't use it unless you actually want the Immediate behaviour. Using Immediate turns off batching (slower) but allows you to directly manipulate states on the GraphicsDevice object between sprites. (Prefer Deferred instead.)

You are setting DepthStencilState.Default (depth reads and writes enabled), which is the default for GraphicsDevice, but the default for SpriteBatch is actually None (depth reads and writes disabled).

Now here's the bit where I have to guess (because you haven't provided enough code, and this is a tricky hardware-dependent problem):

You've set your near plane to 0, and you're drawing things at a Z-position of 0, which is right on the border of the valid region of the depth buffer. I would hazard a guess it has something to do with this. You might try moving your near plane back, moving your Z-position forward, and/or disabling the depth buffer.

  • \$\begingroup\$ The SpriteSortMode thing was quite interesting. However, modifying the Z position didn't work at all. \$\endgroup\$ Jun 24, 2011 at 7:28
  • \$\begingroup\$ I added more details in the original post. \$\endgroup\$ Jun 24, 2011 at 7:42
  • \$\begingroup\$ I'm not 100% sure this is exactly right, in XNA4 (as far as I understand) all SpriteBatch.Begin(...) calls immediately set some device states that you might have to reset afterwards. The only thing SpriteSortMode.Immediately changes is if the calls are done immediately on the graphics device or if the calls are batched until SpriteBatch.End() is called. However I know Andrew is quite a lot deeper into XNA than I am, I feel like I had to point this out. \$\endgroup\$
    – Roy T.
    Jun 24, 2011 at 8:57
  • \$\begingroup\$ The entire state gets set in Begin for Immediate and in End (just before everything is drawn) for every other sort mode. The idea is that you can start filling a (non-immediate) SpriteBatch in parallel with other drawing operations. It basically acts as a buffer. Also SpriteBatch doesn't ever reset state when it's finished (ref). In 3.1, Immediate was draw-lazy (fastest), in 4.0 it's draw-always (slowest, no batching). \$\endgroup\$ Jun 24, 2011 at 10:27
  • \$\begingroup\$ I tried moving the Z coordinate to "5" or "0.5" etc. Still no result! \$\endgroup\$ Jun 24, 2011 at 19:08

Be careful, NVIDIA silently upgrades your incorrect set pixelshader/vertexshader versions. ATI will fail. Use the DirectX SDK to check for warnings. My pixelshader was set to 3.0 and my (spriteBatch) Vertex shader to 2.0...


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .